home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / gnu_oleo_1_2_2.lha / oleo-1.2.2 / io-term.c < prev    next >
C/C++ Source or Header  |  1993-03-03  |  95KB  |  4,537 lines

  1. /*    Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ctype.h>
  20. #include <errno.h>
  21. #include <fcntl.h>
  22. #include <stdio.h>
  23. #include <signal.h>
  24. #include <sys/types.h>
  25. #ifdef I_IOCTL
  26. #include <sys/ioctl.h>
  27. #endif
  28.  
  29. #include "getopt.h"
  30. #include "funcdef.h"
  31. #define obstack_chunk_alloc ck_malloc
  32. #define obstack_chunk_free free
  33. #include "obstack.h"
  34. #include "sysdef.h"
  35. #include "global.h"
  36. #include "cell.h"
  37. #include "cmd.h"
  38. #include "init.h"
  39. #include "utils.h"
  40. #include "regions.h"
  41. #include "ref.h"
  42. #include "lists.h"
  43. #include "line.h"
  44. #define DEFINE_IO_VARS 1
  45. #include "io-abstract.h"
  46. #include "io-generic.h"
  47. #include "io-utils.h"
  48. #include "io-edit.h"
  49. #include "io-term.h"
  50. #include "io-x11.h"
  51. #include "io-curses.h"
  52. #include "window.h"
  53. #include "sylk.h"
  54. #include "font.h"
  55. #include "print.h"
  56.  
  57. /* External spreadsheet functions */
  58. #ifdef USE_DLD
  59. /* If we're using dynamic linking, we get the names of the
  60.        functions to call by prepending the basename of save_name onto
  61.            _read_file
  62.            _write_file
  63.            _set_options
  64.            _show_options
  65.        so, if the file is sylk.o , the functions are named
  66.            sylk_read_file
  67.            sylk_write_file
  68.            sylk_set_options
  69.            sylk_show_options
  70.            */
  71. char *io_name;
  72. #else
  73. #include "sylk.h"
  74. #include "oleofile.h"
  75. #include "sc.h"
  76. #include "list.h"
  77. #endif
  78.  
  79. const char oleo_version_string[] = "Oleo version 1.2.2";
  80.  
  81.  
  82. #ifdef __STDC__
  83. static void got_sig (int);
  84. /* Routines for manipulating key bindings */
  85. static void do_bind_key (struct keymap *, int, int, int);
  86. static void desc_map (struct keymap *);
  87.  
  88. /* File I/O functions */
  89. static FILE *open_file (char *, struct line *, char *);
  90. static void close_file (struct line *, FILE *);
  91.  
  92. /* Routines for putting info into 'struct rng's */
  93. static int get_two_ranges (char *, struct rng *, struct rng *, struct line *);
  94. static FILE *get_range_and_file (char *, struct rng *, struct line *);
  95. static char *get_range_and_font (char *, struct rng *, struct line *);
  96. static int get_a_range (char *, struct rng *, struct line *);
  97. static int get_abs_rng (char **, struct rng *);
  98.  
  99. /* Routines for converting text<-->cell_format */
  100. static int str_to_fmt (char *);
  101.  
  102. /* Routines for converting text<-->cell_jst */
  103. static int chr_to_jst (int);
  104.  
  105. /* Routines for implementing user commands */
  106. void play_cell (void);
  107.  
  108. /* Backends for other functions */
  109. static int do_set_option (char *);
  110.  
  111.  
  112. /* Spreadsheet (global) functions declared in this file */
  113.  
  114.  
  115. int main (int, char **);
  116. void map_chr (int);
  117. extern void clear_spreadsheet (void);
  118. char *cell_name (CELLREF, CELLREF);
  119. char *range_name (struct rng *);
  120. char *fmt_to_str (int);
  121. char *jst_to_str (int);
  122. char *col_to_str (CELLREF);
  123. /* The user commands that are defined in this file. . . */
  124. extern void copy_region (void);
  125. extern void copy_values_region (void);
  126. extern void set_format (void);
  127. extern void move_region (struct rng *, struct rng *);
  128. extern void delete_region (void);
  129. extern void insert_row (void);
  130. extern void insert_col (void);
  131. extern void delete_row (void);
  132. extern void delete_col (void);
  133. extern void format_area (struct rng *);
  134. extern void open_window (char *);
  135. extern void close_window (char *);
  136. extern void hsplit_window (void);
  137. extern void vsplit_window (void);
  138. extern void delete_window (void);
  139. extern void delete_other_windows (void);
  140. extern void goto_window (char *);
  141. extern void other_window (void);
  142. extern void print_region (struct rng *, char *);
  143. extern void psprint_region_cmd (FILE *, struct rng *);
  144.  
  145. static void end_macro (void);
  146. static void do_break_cmd (void);
  147. static void set_default (void);
  148. static void quit_cmd (void);
  149. static void set_usr_fmt (char *);
  150. static void set_var (char *);
  151. static void show_var (char *);
  152. static void show_all_var (void);
  153. static void write_variables (FILE *);
  154. static void read_variables (FILE *);
  155. static void recalc_cmd (void);
  156. static void bind_key_cmd (char *);
  157. static void desc_key_cmd (void);
  158. static void read_cmds_cmd (FILE *);
  159. static void write_keys_cmd (FILE *);
  160. static void write_cmd (FILE *);
  161. static void read_cmd (FILE *);
  162. static void read_merge_cmd (FILE *);
  163. static void kill_all_cmd (void);
  164. static void sort_region_cmd (char *);
  165. static void write_reg_cmd (FILE *, struct rng *);
  166. static void start_macro (void);
  167. void execute_cmd (char *);
  168. static void interact_macro_cmd (void);
  169. static void goto_region (struct rng *);
  170. static void upper_left (void);
  171. static void lower_left (void);
  172. static void upper_right (void);
  173. static void lower_right (void);
  174. extern void exchange_point_and_mark (void);
  175. static void mark_cell_cmd (void);
  176. static void unmark_cmd (void);
  177. static void do_input_cmd (int, int);
  178. static void set_region_formula (char *, struct rng *);
  179. static void set_cell_formula (char *, CELLREF, CELLREF);
  180. static void format_cell_cmd (void);
  181. static void kill_cell_cmd (void);
  182. static void digit_cmd (int);
  183. static void show_options (void);
  184. static void bound_macro (int);
  185. static void make_keymap (char *);
  186. static void set_cell_font_cmd (char *);
  187. static void set_area_font_cmd (char *, struct rng *);
  188. static void scan_cell_cursor (int);
  189. static void shift_cell_cursor (int);
  190. static void scroll_cell_cursor (int);
  191. static void recenter_cur_win (void);
  192. static void repaint (void);
  193. static void mouse_goto_cmd (void);
  194. static void mouse_mark_cmd (void);
  195. static void mouse_mark_and_goto_cmd (void);
  196. static void set_page_size_cmd (char *);
  197. void toggle_load_hooks (void);
  198. void read_file_and_run_hooks (FILE *, int);
  199. #else
  200. static void got_sig ();
  201. /* Routines for manipulating key bindings */
  202. static void do_bind_key ();
  203. static void desc_map ();
  204.  
  205. /* File I/O functions */
  206. static FILE *open_file ();
  207. static void close_file ();
  208.  
  209. /* Routines for putting info into 'struct rng's */
  210. static int get_two_ranges ();
  211. static FILE *get_range_and_file ();
  212. static char *get_range_and_font ();
  213. static int get_a_range ();
  214. static int get_abs_rng ();
  215.  
  216. /* Routines for converting text<-->cell_format */
  217. static int str_to_fmt ();
  218.  
  219. /* Routines for converting text<-->cell_jst */
  220. static int chr_to_jst ();
  221.  
  222. /* Routines for implementing user commands */
  223. void play_cell ();
  224.  
  225. /* Backends for other functions */
  226. static int do_set_option ();
  227.  
  228.  
  229. /* Spreadsheet (global) functions declared in this file */
  230.  
  231.  
  232. int main ();
  233. extern void clear_spreadsheet ();
  234. char *cell_name ();
  235. char *range_name ();
  236. char *fmt_to_str ();
  237. char *jst_to_str ();
  238. char *col_to_str ();
  239. /* The user commands that are defined in this file. . . */
  240. extern void copy_region ();
  241. extern void copy_values_region ();
  242. extern void set_format ();
  243. extern void move_region ();
  244. extern void delete_region ();
  245. extern void insert_row ();
  246. extern void insert_col ();
  247. extern void delete_row ();
  248. extern void delete_col ();
  249. extern void format_area ();
  250. extern void open_window ();
  251. extern void hsplit_window ();
  252. extern void vsplit_window ();
  253. extern void delete_window ();
  254. extern void delete_other_windows ();
  255. extern void close_window ();
  256. extern void goto_window ();
  257. extern void other_window ();
  258. extern void print_region ();
  259. extern void psprint_region_cmd ();
  260.  
  261. static void do_debug ();
  262. static void end_macro ();
  263. static void do_break_cmd ();
  264. static void set_default ();
  265. static void quit_cmd ();
  266. static void set_usr_fmt ();
  267. static void set_var ();
  268. static void show_var ();
  269. static void show_all_var ();
  270. static void write_variables ();
  271. static void read_variables ();
  272. static void recalc_cmd ();
  273. static void bind_key_cmd ();
  274. static void desc_key_cmd ();
  275. static void where_is_cmd ();
  276. static void read_cmds_cmd ();
  277. static void write_keys_cmd ();
  278. static void write_cmd ();
  279. static void read_cmd ();
  280. static void read_merge_cmd ();
  281. static void kill_all_cmd ();
  282. static void sort_region_cmd ();
  283. static void write_reg_cmd ();
  284. static void start_macro ();
  285. void execute_cmd ();
  286. static void interact_macro_cmd ();
  287. static void goto_region ();
  288. static void upper_left ();
  289. static void lower_left ();
  290. static void upper_right ();
  291. static void lower_right ();
  292. extern void exchange_point_and_mark ();
  293. static void mark_cell_cmd ();
  294. static void unmark_cmd ();
  295. static void do_input_cmd ();
  296. static void set_region_formula ();
  297. static void set_cell_formula ();
  298. static void format_cell_cmd ();
  299. static void kill_cell_cmd ();
  300. static void digit_cmd ();
  301. static void show_options ();
  302. static void bound_macro ();
  303. static void make_keymap ();
  304. static void set_cell_font_cmd ();
  305. static void set_area_font_cmd ();
  306. static void scan_cell_cursor ();
  307. static void shift_cell_cursor ();
  308. static void scroll_cell_cursor ();
  309. static void recenter_cur_win ();
  310. static void repaint ();
  311. static void mouse_goto_cmd ();
  312. static void mouse_mark_cmd ();
  313. static void mouse_mark_and_goto_cmd ();
  314. static void set_page_size_cmd ();
  315. void toggle_load_hooks ();
  316. void read_file_and_run_hooks ();
  317.  
  318.  
  319. #endif
  320.  
  321.  
  322. char *ename[] =
  323. {
  324.   "#WHAT?",
  325.   "#ERROR", "#BAD_INPUT", "#NON_NUMBER", "#NON_STRING",
  326.   "#NON_BOOL", "#NON_RANGE", "#OUT_OF_RANGE", "#NO_VALUES",
  327.   "#DIV_BY_ZERO", "#BAD_NAME", "#NOT_AVAIL", "#PARSE_ERROR",
  328.   "#NEED_OPEN", "#NEED_CLOSE", "#NEED_QUOTE", "#UNK_CHAR",
  329.   "#UNK_FUNC",
  330.   0
  331. };
  332.  
  333. char tname[] = "#TRUE";
  334. char fname[] = "#FALSE";
  335.  
  336. struct line val_line;
  337. struct line fmt_line;
  338. struct line wid_line;
  339. struct line hgt_line;
  340. struct line font_line;
  341.  
  342. /* Lines 'a' through 'z' */
  343. struct line in_line[26];
  344.  
  345. unsigned short default_width = 8;
  346. unsigned short default_height = 1;
  347. unsigned short saved_default_width = 8;
  348. unsigned short saved_default_height = 1;
  349. int default_jst = JST_LFT;
  350. int default_fmt = FMT_GEN;
  351. int default_lock = LCK_UNL;
  352.  
  353. int term_flag;
  354.  
  355. extern char print_buf[];
  356.  
  357. struct keymap **the_maps;
  358. char **map_names;
  359. int num_maps;
  360.  
  361. struct cmd_func **the_funcs;
  362. int num_funcs;
  363.  
  364.  
  365. /* For lines that take text input, the second letter (eg 'ta' or 'fdr')
  366.    specifies which struct line to use to contain the text generated for that
  367.    command.  That way, the command will have the appropriate defaults, etc.
  368.    Currently 'a' through 'n' are used (?).
  369.     a    set options
  370.     b    set/show variables
  371.     c    read/write keymap
  372.     d    read/write file
  373.     e    read-merge    write-region
  374.     f    copy region/copy values region
  375.     g    format-region
  376.     h    move-region
  377.     i    print-region
  378.     j    sort-region
  379.     k    delete-region
  380.     l    execute-command
  381.     m    goto-cell
  382.     n    open-window
  383.     o    close-window
  384.     p    page size
  385.     q    bind-key
  386.     r    set-user-format
  387.     s    create-keymap
  388.     t    font names
  389.     u    point size
  390.     v    formulas
  391.     w    variable files
  392.     x    command name
  393.  */
  394. static struct cmd_func *end_macro_cmd;
  395. static struct cmd_func *digit_0_cmd;
  396. static struct cmd_func *digit_9_cmd;
  397.  
  398.  
  399.  
  400. static struct cmd_func cmd_funcs[] =
  401. {
  402.   {"unbound", 0, ALL, 0},
  403. /* The location of these motion commands in this array is assumed elsewhere in */
  404. /* the code.  Other motion and scrolling commands are also assumed to be in a */
  405. /* particular order. */
  406.   {"up-cell", "n0", ALL, shift_cell_cursor},
  407.   {"down-cell", "n1", ALL, shift_cell_cursor},
  408.   {"right-cell", "n2", ALL, shift_cell_cursor},
  409.   {"left-cell", "n3", ALL, shift_cell_cursor},
  410.   {"upright-cell", "n4", ALL, shift_cell_cursor},
  411.   {"upleft-cell", "n5", ALL, shift_cell_cursor},
  412.   {"downright-cell", "n6", ALL, shift_cell_cursor},
  413.   {"downleft-cell", "n7", ALL, shift_cell_cursor},
  414.  
  415.   {"scroll-up", "n0", ALL, scroll_cell_cursor},
  416.   {"scroll-down", "n1", ALL, scroll_cell_cursor},
  417.   {"scroll-right", "n2", ALL, scroll_cell_cursor},
  418.   {"scroll-left", "n3", ALL, scroll_cell_cursor},
  419.   {"scroll-upright", "n4", ALL, scroll_cell_cursor},
  420.   {"scroll-upleft", "n5", ALL, scroll_cell_cursor},
  421.   {"scroll-downright", "n6", ALL, scroll_cell_cursor},
  422.   {"scroll-downleft", "n7", ALL, scroll_cell_cursor},
  423.  
  424.   {"scan-up", "n0", ALL, scan_cell_cursor},
  425.   {"scan-down", "n1", ALL, scan_cell_cursor},
  426.   {"scan-right", "n2", ALL, scan_cell_cursor},
  427.   {"scan-left", "n3", ALL, scan_cell_cursor},
  428.  
  429.   {"break", 0, ALL | BRK, do_break_cmd},
  430.   {"recenter-window", 0, ALL, recenter_cur_win},
  431.   {"set-option", "ta", ALL, set_options},
  432.   {"set-defaults", "T", ALL, set_default},
  433.   {"quit", "C", ALL, quit_cmd},
  434.   {"redraw-screen", 0, ALL, repaint},
  435.   {"set-user-format", "trT", ALL, set_usr_fmt},
  436.  
  437. /* If you change the line used by {set,show}-variable, you must change
  438.    {set,show}_var to use the correct line, else bad things will happen */
  439.   {"set-variable", "tb", ALL, set_var},
  440.   {"show-variable", "tb", ALL, show_var},
  441.   {"show-all-variables", 0, ALL, show_all_var},
  442.   {"write-variables", "fww", ALL, write_variables},
  443.   {"read-variables", "fwr", ALL, read_variables},
  444.  
  445.   {"recalculate", 0, ALL, recalc_cmd},
  446.   {"bind-key", "tqT", ALL, bind_key_cmd},
  447.   {"describe-key", "T", ALL, desc_key_cmd},
  448. /*  {"where-is", "tx", ALL, where_is_cmd}, */
  449.   {"read-commands", "fcr", ALL, read_cmds_cmd},
  450.   {"write-keys", "fcw", ALL, write_keys_cmd},
  451.  
  452. /* If you change the line used by {read,write}-file, you must change
  453.    main() to use the correct line, else chaos will erupt */
  454.   {"save-spreadsheet", "fdw", ALL, write_cmd},
  455.   {"visit-spreadsheet", "Cfdr", ALL, read_cmd},
  456.   {"merge-spreadsheet", "fer", ALL, read_merge_cmd},
  457.   {"clear-spreadsheet", "C", ALL, kill_all_cmd},
  458.  
  459.   {"copy-region", "Rf", ALL, copy_region},
  460.   {"copy-values-in-region", "Rf", ALL, copy_values_region},
  461.   {"format-region", "rg", ALL, format_area},
  462.   {"move-region", "Rh", ALL, move_region},
  463.   {"insert-row", 0, ALL, insert_row },
  464.   {"insert-col", 0, ALL, insert_col },
  465.   {"delete-row", 0, ALL, delete_row },
  466.   {"delete-col", 0, ALL, delete_col },
  467.   {"print-region", "Fi", ALL, print_region},
  468.   {"psprint-region", "Fi", ALL, psprint_region_cmd},
  469.   {"set-page-size", "tp", ALL, set_page_size_cmd },
  470.   {"set-default-ps-font", "tt", ALL, set_ps_font_cmd },
  471. #ifdef HAVE_X11_X_H
  472.   {"set-default-font", "tt", ALL, set_x_default_font },
  473.   {"set-default-point-size", "tu", ALL, set_x_default_point_size },
  474. #endif
  475.  
  476.   {"sort-region", "tj", ALL, sort_region_cmd},
  477.   {"write-region-to-file", "Fe", ALL, write_reg_cmd},
  478.   {"delete-region", "rk", ALL, delete_region},
  479.  
  480.   {"start-entering-macro", 0, ALL, start_macro},
  481.   {"execute-command", "tl", ALL, execute_cmd},
  482.   {"macro-interactive-here", 0, ALL, interact_macro_cmd},
  483.  
  484. /* If you change which line goto-cell uses, you *must* modify goto_region() */
  485.   {"goto-cell", "rm", ALL, goto_region},
  486.   {"upper-left", 0, ALL, upper_left},
  487.   {"lower-left", 0, ALL, lower_left},
  488.   {"upper-right", 0, ALL, upper_right},
  489.   {"lower-right", 0, ALL, lower_right},
  490.   {"exchange-point-and-mark", 0, ALL, exchange_point_and_mark },
  491.   {"mark-cell", 0, ALL, mark_cell_cmd},
  492.   {"clear-mark", 0, ALL, unmark_cmd},
  493.   {"edit-cell", "T0", ALL | WTH_CHR, do_input_cmd},
  494.   {"edit-value-cell", "T1", ALL | WTH_CHR, do_input_cmd},
  495.   {"format-cell", "T", ALL, format_cell_cmd},
  496.   {"delete-cell", 0, ALL, kill_cell_cmd},
  497.   {"edit-cell-with-default", "T3", ALL | WTH_CHR, do_input_cmd},
  498.   {"set-region-formula", "Sv", ALL, set_region_formula},
  499.  
  500.   {"digit-0", "N", ALL | NC, digit_cmd},
  501.   {"digit-1", "N", ALL | NC, digit_cmd},
  502.   {"digit-2", "N", ALL | NC, digit_cmd},
  503.   {"digit-3", "N", ALL | NC, digit_cmd},
  504.   {"digit-4", "N", ALL | NC, digit_cmd},
  505.   {"digit-5", "N", ALL | NC, digit_cmd},
  506.   {"digit-6", "N", ALL | NC, digit_cmd},
  507.   {"digit-7", "N", ALL | NC, digit_cmd},
  508.   {"digit-8", "N", ALL | NC, digit_cmd},
  509.   {"digit-9", "N", ALL | NC, digit_cmd},
  510.  
  511.   {"enter-text-in-cell", "T2", WTH_CHR | ALL, do_input_cmd},
  512.  
  513.   {"show-options", 0, ALL, show_options},
  514.   {"play_cell", 0, ALL, play_cell},
  515.   {"open-window", "tn", ALL, open_window},
  516.   {"split-window-horizontally", 0, ALL, hsplit_window},
  517.   {"split-window-vertically", 0, ALL, vsplit_window},
  518.   {"delete-window", 0, ALL, delete_window},
  519.   {"delete-other-windows", 0, ALL, delete_other_windows},
  520.   {"close-window", "to", ALL, close_window},
  521.   {"goto-window", "to", ALL, goto_window},
  522.   {"other-window", 0, ALL, other_window},
  523.  
  524.   {"stop-entering-macro", 0, ALL, end_macro},
  525.  
  526.   {"create-keymap", "ts", ALL, make_keymap},
  527.  
  528.   {"set-cell-font", "tt", ALL, set_cell_font_cmd},
  529.   {"define-font", "tt", ALL, define_font},
  530.   {"set-region-font", "St", ALL, set_area_font_cmd},
  531.   {"toggle-load-hooks", 0, ALL, toggle_load_hooks },
  532.  
  533.   {    "mouse-goto",        0,    ALL,    mouse_goto_cmd },
  534.   {    "mouse-mark",        0,    ALL,    mouse_mark_cmd },
  535.   {    "mouse-mark-and-goto",    0,    ALL,    mouse_mark_and_goto_cmd },
  536.   {"bound-menu", 0, WTH_CHR | ALL, 0},
  537.  
  538.   {0, 0, 0, 0}
  539.  
  540. };
  541.  
  542.  
  543.  
  544. fd_set read_fd_set;
  545. fd_set read_pending_fd_set;
  546. fd_set exception_fd_set;
  547. fd_set exception_pending_fd_set;
  548.  
  549. /* Block until we get a signal (unless system calls restart), 
  550.  * can do io or, until we timeout (timeout is specified in seconds,
  551.  * 0 means block indefinately). 
  552.  */
  553. #ifdef __STDC__
  554. static void
  555. block_until_excitment (int timeout_seconds)
  556. #else
  557. static void
  558. block_until_excitment (timeout_seconds)
  559.      int timeout_seconds;
  560. #endif
  561. {
  562.   int ret;
  563.   struct timeval timeout;
  564.   struct timeval * time_p = 0;
  565.  
  566.   if (timeout_seconds)
  567.     {
  568.       timeout.tv_sec = timeout_seconds;
  569.       timeout.tv_usec = 0;
  570.       time_p = &timeout;
  571.     }
  572.   bcopy ((char *)&read_fd_set, (char *)&read_pending_fd_set, sizeof (fd_set));
  573.   bcopy ((char *)&exception_fd_set,
  574.      (char *)&exception_pending_fd_set, sizeof (fd_set));
  575.   ret = select (FD_SETSIZE,
  576.         &read_pending_fd_set, 0, &exception_pending_fd_set, time_p);
  577.   if (ret < 0)
  578.     {
  579.       FD_ZERO (&read_pending_fd_set);
  580.       FD_ZERO (&exception_pending_fd_set);
  581.     }
  582. }
  583.  
  584. /* This is the main interact loop.  As quickly as possible
  585.  * it returns a character from the keyboard.  While waiting,
  586.  * it updates cells and the display.  If a macro is being defined,
  587.  * this function save characters in the macro.
  588.  */
  589.  
  590. int 
  591. real_get_chr ()
  592. {
  593.   int ch;            /* The char that will be returned. */
  594.  
  595.   /* Characters with the meta bit set are returned as
  596.    * two characters: ESC and a non-meta character.
  597.    * This buffers the non-meta character between calls.
  598.    * The value is 0 if no character is buffered, C+1 if
  599.    * C is buffered.
  600.    */
  601.   static int saved_char;
  602.  
  603.   /* A buffer of characters read in one burst from the kbd. */
  604.   static char ibuf[256];
  605.   static int i_in;        /* chars buffered */
  606.   static int i_cnt;        /* buffer position */
  607.  
  608.   deal_alarm ();
  609.   if (saved_char)
  610.     {
  611.       ch = saved_char - 1;
  612.       saved_char = 0;
  613.       goto fini;
  614.     }
  615.  
  616.   if (i_cnt)
  617.     {
  618.       ch = ibuf[i_cnt++];
  619.       if (i_cnt == i_in)
  620.     i_cnt = i_in = 0;
  621.       goto fini;
  622.     }
  623.  
  624.   /* This loop until a character can be read. */
  625.   while (!io_input_avail ())
  626.     {
  627.       deal_alarm ();
  628.       io_scan_for_input (0);
  629.       if (!io_input_avail ())
  630.     {
  631.       ++current_cycle;
  632.       if (auto_recalc && eval_next_cell ())
  633.         {
  634.           if (bkgrnd_recalc)
  635.         while (!io_input_avail () && eval_next_cell ())
  636.           io_scan_for_input (0);
  637.           else
  638.         while (eval_next_cell ())
  639.           ;
  640.           io_scan_for_input (0);
  641.           if (!io_input_avail ())
  642.         io_redisp ();
  643.           io_flush ();
  644.           io_scan_for_input (0);
  645.         }
  646.       else
  647.         {
  648.           int timeout = (alarm_active
  649.                  ? (alarm_seconds == 1
  650.                 ? 1
  651.                 : (alarm_seconds / 2))
  652.                  : 0);
  653.                  
  654.           --current_cycle;
  655.           io_redisp ();
  656.           io_flush ();
  657.           io_scan_for_input (0);
  658.           if (!io_input_avail ())
  659.         block_until_excitment (timeout);
  660.         }
  661.     }
  662.     }
  663.  
  664.   {
  665.     int ret;
  666.     ret = io_read_kbd (ibuf, sizeof (ibuf));
  667.     if (ret == 1)
  668.       {
  669.     ch = ibuf[0];
  670.     goto fini;
  671.       }
  672.     if (ret > 1)
  673.       {
  674.     i_cnt = 1;
  675.     i_in = ret;
  676.     ch = ibuf[0];
  677.     goto fini;
  678.       }
  679.     if (ret == 0 || (errno != EWOULDBLOCK && errno != EINTR))
  680.       return EOF;
  681.   }
  682.  
  683. fini:
  684.  
  685.   if (ch & 0x80)
  686.     {
  687.       saved_char = 1 + (ch & 0x7f);
  688.       ch = CTRL ('[');
  689.     }
  690.  
  691.   if (making_macro)
  692.     {
  693.       /* This is stoopid and should be fixed.
  694.        * Macros (and other cell strings) should be 
  695.        * `struct line' and not c-strings.   -tl
  696.        */
  697.       if (ch == 0)
  698.     *making_macro++ = 0x80 | 'a';
  699.       else if (ch == '{')
  700.     *making_macro++ = 0x80 | 'b';
  701.       else
  702.     *making_macro++ = ch;
  703.       if (making_macro >= making_macro_start + making_macro_size)
  704.     {
  705.       making_macro_start =
  706.         ck_realloc (making_macro_start, 5 + making_macro_size * 2);
  707.       making_macro = making_macro_start + making_macro_size;
  708.       making_macro_size *= 2;
  709.     }
  710.     }
  711.   return ch;
  712. }
  713.  
  714.  
  715. CELLREF setrow, setcol;
  716.  
  717. CELLREF curow = MIN_ROW, cucol = MIN_COL;
  718.  
  719. CELLREF mkrow = NON_ROW, mkcol = NON_COL;
  720. int cur_chr;
  721. struct cmd_func *cur_cmd;
  722. short cur_vector;
  723. unsigned int how_many = 1;
  724. char *macro_func_arg = 0;
  725.  
  726. int n_bound_macros;
  727. struct rng *bound_macros;
  728. int bound_macro_vec;
  729.  
  730. /* This variable is non-zero if the spreadsheet has been changed in any way */
  731. int modified = 0;
  732.  
  733. /* User settable options */
  734. int bkgrnd_recalc = 1;
  735. int auto_recalc = 1;
  736. int a0 = 0;
  737.  
  738. /* This is how frequently the alarm should go off. */
  739. unsigned int alarm_seconds = 1;
  740. unsigned int alarm_active = 0;    /* Whether or not the alarm matters. */
  741.  
  742. #ifdef __STDC__
  743. void (*read_file) (FILE *, int) = oleo_read_file;
  744. void (*write_file) (FILE *, struct rng *) = oleo_write_file;
  745. int (*set_file_opts) (int, char *) = oleo_set_options;
  746. void (*show_file_opts) () = oleo_show_options;
  747. #else
  748. void (*read_file) () = oleo_read_file;
  749. void (*write_file) () = oleo_write_file;
  750. int (*set_file_opts) () = oleo_set_options;
  751. void (*show_file_opts) () = oleo_show_options;
  752. #endif
  753.  
  754. const int colmagic[] =
  755. {0, 0, 1, -1, 1, -1, 1, -1, 0};
  756. const int rowmagic[] =
  757. {-1, 1, 0, 0, -1, -1, 1, 1, 0};
  758.  
  759.  
  760. struct macro *rmac = 0;
  761. struct obstack macro_stack;
  762. unsigned char *making_macro;
  763. unsigned char *making_macro_start;
  764. unsigned int making_macro_size;
  765.  
  766.  
  767.  
  768. static int run_load_hooks = 1;
  769. static char load_hooks_string[] = "load_hooks";
  770.  
  771. void
  772. read_file_and_run_hooks (fp, ismerge)
  773.      FILE * fp;
  774.      int ismerge;
  775. {
  776.   (*read_file)(fp, ismerge);
  777.   if (run_load_hooks)
  778.     {
  779.       struct var * v;
  780.       v = find_var (load_hooks_string, sizeof (load_hooks_string) - 1);
  781.       if (v && v->var_flags != VAR_UNDEF)
  782.     execute_cmd (load_hooks_string);
  783.     }
  784. }
  785.  
  786. void
  787. toggle_load_hooks ()
  788. {
  789.   if (!how_many && run_load_hooks)
  790.     {
  791.       run_load_hooks = 0;
  792.       io_info_msg ("load hooks turned off");
  793.     }
  794.   else
  795.     {
  796.       run_load_hooks = 1;
  797.       io_info_msg ("load hooks turned on");
  798.     }
  799. }
  800.  
  801.  
  802.  
  803. /* Read a character.  If we're in a macro, read from the macro. . . */
  804. int
  805. get_chr ()
  806. {
  807.   int ch;
  808.  
  809.   if (rmac)
  810.     {
  811.       ch = *(rmac->mac_exe++);
  812.       switch (ch)
  813.     {
  814.     case '{':        /* What else can we do? */
  815.     case '\0':
  816.       --(rmac->mac_exe);
  817.       break;
  818.  
  819.     case (0x80 | 'a'):
  820.       ch = 0;
  821.       break;
  822.  
  823.     case (0x80 | 'b'):
  824.       ch = '{';
  825.       break;
  826.     default:
  827.       break;
  828.     }
  829.     }
  830.   else
  831.     ch = real_get_chr ();
  832.   return ch;
  833. }
  834.  
  835. void 
  836. open_window (text)
  837.      char *text;
  838. {
  839.   int hv;
  840.   int where;
  841.  
  842.   while (*text == ' ')
  843.     text++;
  844.  
  845.   if (*text == 'h' || *text == 'H')
  846.     hv = 0;
  847.   else if (*text == 'v' || *text == 'V')
  848.     hv = 1;
  849.   else
  850.     {
  851.       io_error_msg ("Open 'h'orizontal or 'v'ertical window, not '%s'", text);
  852.       return;
  853.     }
  854.   where = atoi (text + 1);
  855.   while (isspace (*text))
  856.     ++text;
  857.   while (isalnum (*text))
  858.     ++text;
  859.   while (isspace (*text))
  860.     ++text;
  861.   if (*text == '%')
  862.     {
  863.       where *= (hv
  864.         ? (cwin->numr + (cwin->lh_wid ? label_rows : 0))
  865.         : (cwin->numc + cwin->lh_wid));
  866.       where /= 100;
  867.     }
  868.   io_win_open (hv, where);
  869. }
  870.  
  871. void
  872. hsplit_window ()
  873. {
  874.   open_window ("h50%");
  875. }
  876.  
  877.  
  878. void
  879. vsplit_window ()
  880. {
  881.   open_window ("v50%");
  882. }
  883.  
  884.  
  885. void 
  886. close_window (text)
  887.      char *text;
  888. {
  889.   int num;
  890.  
  891.   num = atoi (text) - 1;
  892.  
  893.   if (num < 0 || num >= nwin)
  894.     {
  895.       io_error_msg ("Window %num?", text);
  896.       return;
  897.     }
  898.   if (nwin == 1)
  899.     {
  900.       io_error_msg ("You can't close the last window!");
  901.       return;
  902.     }
  903.   io_win_close (&wins[num]);
  904. }
  905.  
  906. void 
  907. delete_window ()
  908. {
  909.   io_win_close (cwin);
  910. }
  911.  
  912. void
  913. delete_other_windows ()
  914. {
  915.   if (nwin > 1)
  916.     {
  917.       CELLREF r = curow;
  918.       CELLREF c = cucol;
  919.       while (nwin > 1)
  920.     io_win_close (cwin);
  921.       io_move_cell_cursor (r, c);
  922.     }
  923. }
  924.  
  925. void
  926. goto_window (text)
  927.      char *text;
  928. {
  929.   int n;
  930.   n = atoi (text) - 1;
  931.   if (n < 0 || n > nwin)
  932.     {
  933.       io_error_msg ("Window %s doesn't exist.", text);
  934.       return;
  935.     }
  936.   io_set_cwin (&wins[n]);
  937. }
  938.  
  939. void
  940. exchange_point_and_mark ()
  941. {
  942.   CELLREF r = curow;
  943.   CELLREF c = cucol;
  944.   struct rng rng;
  945.   
  946.   rng.lr = rng.hr = r;
  947.   rng.lc = rng.hc = c;
  948.   goto_region (&rng);
  949.   mkrow = r;
  950.   mkcol = c;
  951.   io_update_status ();
  952. }
  953.  
  954. #ifdef __STDC__
  955. void 
  956. nicely_goto_window (int n)
  957. #else
  958. void 
  959. nicely_goto_window (n)
  960.      int n;
  961. #endif
  962. {
  963.   if (input_active)
  964.     {
  965.       io_cellize_cursor ();
  966.       window_after_input = n;
  967.       input_active = 0;
  968.       return;
  969.     }
  970.   else
  971.     {
  972.       if (window_after_input == n)
  973.     {
  974.       io_inputize_cursor ();
  975.       window_after_input = -1;
  976.       input_active = 1;
  977.     }
  978.       else
  979.     io_set_cwin (&wins[n]);
  980.     }
  981. }
  982.  
  983. void 
  984. other_window ()
  985. {
  986.   int n = cwin - wins;
  987.   if (!input_active)
  988.     n = (n + 1) % nwin;
  989.   nicely_goto_window (n);
  990. }
  991.  
  992. int
  993. set_window_option (set_opt, text)
  994.      int set_opt;
  995.      char *text;
  996. {
  997.   int n;
  998.   int stat;
  999.   static struct opt
  1000.     {
  1001.       char *text;
  1002.       int bits;
  1003.     }
  1004.   opts[] =
  1005.   {
  1006.     {
  1007.       "reverse", WIN_EDGE_REV
  1008.     }
  1009.     ,
  1010.     {
  1011.       "standout", WIN_EDGE_REV
  1012.     }
  1013.     ,
  1014.     {
  1015.       "page", WIN_PAG_HZ | WIN_PAG_VT
  1016.     }
  1017.     ,
  1018.     {
  1019.       "pageh", WIN_PAG_HZ
  1020.     }
  1021.     ,
  1022.     {
  1023.       "pagev", WIN_PAG_VT
  1024.     }
  1025.     ,
  1026.     {
  1027.       "lockh", WIN_LCK_HZ
  1028.     }
  1029.     ,
  1030.     {
  1031.       "lockv", WIN_LCK_VT
  1032.     }
  1033.     ,
  1034.     {
  1035.       "edges", WIN_EDGES
  1036.     }
  1037.   };
  1038.   if ((stat = (!strincmp (text, "status", 6) && isspace (text[6])))
  1039.       || (!strincmp (text, "input", 5) && isspace (text[5])))
  1040.     {
  1041.       int n = set_opt ? atoi (text + 6 + stat) : 0;    /* A little pun. */
  1042.       int new_inp = stat ? user_input : n;
  1043.       int new_stat = stat ? n : user_status;
  1044.       io_set_input_status (new_inp, new_stat, 1);
  1045.     }
  1046.   else if (!strincmp (text, "link", 4))
  1047.     {
  1048.       if (set_opt)
  1049.     {
  1050.       n = atoi (text + 4) - 1;
  1051.       if (n < 0 || n > nwin)
  1052.         io_error_msg ("Can't '%s': window # out of range", text);
  1053.       else
  1054.         cwin->link = n;
  1055.     }
  1056.       else
  1057.     cwin->link = -1;
  1058.     }
  1059.   else if (set_opt && !stricmp (text, "unlink"))
  1060.     cwin->link = -1;
  1061.   else if (set_opt && !strincmp (text, "row ", 4))
  1062.     {
  1063.       text += 4;
  1064.       curow = astol (&text);
  1065.     }
  1066.   else if (set_opt && !strincmp (text, "col ", 4))
  1067.     {
  1068.       text += 4;
  1069.       cucol = astol (&text);
  1070.     }
  1071.   else
  1072.     {
  1073.       for (n = 0; n < sizeof (opts) / sizeof (struct opt); n++)
  1074.     if (!stricmp (text, opts[n].text))
  1075.       {
  1076.         if (set_opt)
  1077.           cwin->flags |= opts[n].bits;
  1078.         else
  1079.           cwin->flags &= ~opts[n].bits;
  1080.         break;
  1081.       }
  1082.  
  1083.       if (n == sizeof (opts) / sizeof (struct opt))
  1084.       return 0;
  1085.     }
  1086.   return 1;
  1087. }
  1088.  
  1089. void
  1090. show_window_options ()
  1091. {
  1092.   int n;
  1093.  
  1094.   cwin->curow = curow;
  1095.   cwin->cucol = cucol;
  1096.   if (user_status)
  1097.     io_text_line ("Status line at %d", user_status);
  1098.   else
  1099.     io_text_line ("Status line disabled.");
  1100.   io_text_line ("");
  1101.   for (n = 0; n < nwin; n++)
  1102.     {
  1103.       int flags = wins[n].flags;
  1104.       io_text_line ("Window #%d showing %s, with cursor at %s",
  1105.             n + 1,
  1106.             range_name (&wins[n].screen),
  1107.             cell_name (wins[n].curow, wins[n].cucol));
  1108.       io_text_line ("   Options:  %sedges (%sreverse)%s%s%s%s",
  1109.             flags & WIN_EDGES ? "" : "no",
  1110.             flags & WIN_EDGE_REV ? "" : "no",
  1111.             flags & WIN_PAG_HZ ? ", pageh" : "",
  1112.             flags & WIN_PAG_VT ? ", pagev" : "",
  1113.             flags & WIN_LCK_HZ ? ", lockh" : "",
  1114.             flags & WIN_LCK_VT ? ", lockv" : "");
  1115.       if (wins[n].link != -1)
  1116.     io_text_line ("Linked to window %d", wins[n].link + 1);
  1117.     }
  1118. }
  1119.  
  1120. static struct cmd_func *
  1121. find_func (table, name)
  1122.      struct cmd_func *table;
  1123.      char *name;
  1124. {
  1125.   while (table->func_name)
  1126.     if (!strcmp (name, table->func_name))
  1127.       return table;
  1128.     else
  1129.       ++table;
  1130.   return 0;
  1131. }
  1132.  
  1133. void
  1134. init_maps ()
  1135. {
  1136.   num_maps = 0;
  1137.   the_maps = 0;
  1138.   map_names = 0;
  1139.  
  1140.   the_funcs = ck_malloc (sizeof (struct cmd_func *) * 2);
  1141.   num_funcs = 2;
  1142.   the_funcs[0] = &cmd_funcs[0];
  1143.   the_funcs[1] = &edit_funcs[0];
  1144.  
  1145.   run_init_cmds ();
  1146.  
  1147.   end_macro_cmd = find_func (cmd_funcs, "stop-entering-macro");
  1148.   digit_0_cmd = find_func (cmd_funcs, "digit-0");
  1149.   digit_9_cmd = find_func (cmd_funcs, "digit-9");
  1150. }
  1151.  
  1152. static int 
  1153. add_usr_cmds (new_cmds)
  1154.      struct cmd_func *new_cmds;
  1155. {
  1156.   num_funcs++;
  1157.   the_funcs = ck_realloc (the_funcs, num_funcs * sizeof (struct cmd_func *));
  1158.   the_funcs[num_funcs - 1] = new_cmds;
  1159.   return num_funcs - 1;
  1160. }
  1161.  
  1162. #ifdef USE_DLD
  1163. static int 
  1164. add_usr_maps (new_maps)
  1165.      struct keymap **new_maps;
  1166. {
  1167.   int n;
  1168.  
  1169.   for (n = 1; new_maps[n]; n++)
  1170.     ;
  1171.   the_maps = ck_realloc (the_maps, (n + num_maps) * sizeof (struct keymap *));
  1172.   bcopy (new_maps, &the_maps[num_maps], n * sizeof (struct keymap *));
  1173.   num_maps += n;
  1174.   return num_maps - n;
  1175. }
  1176.  
  1177. #endif
  1178.  
  1179. static int last_map;
  1180.  
  1181.  
  1182. static char * disclaimer[] = 
  1183. {
  1184.   " Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation,Inc.\n",
  1185.   "There is ABSOLUTELY NO WARRANTY for Oleo; see the file COPYING\n",
  1186.   "for details.  Oleo is free software and you are welcome to distribute\n",
  1187.   "copies of it under certain conditions; see the file COPYING to see the\n",
  1188.   "conditions.\n\n",
  1189.   0
  1190. };
  1191.  
  1192. static char short_options[] = "Vqfh";
  1193. static struct option long_options[] =
  1194. {
  1195.   {"version", 0, NULL, 'V'},
  1196.   {"quiet", 0, NULL, 'q'},
  1197.   {"ignore-init-file", 0, NULL, 'f'},
  1198.   {"nw", 0, NULL, 'x'},
  1199.   {"help", 0, NULL, 'h'},
  1200.   {NULL, 0, NULL, 0}
  1201. };
  1202.  
  1203. static char * usage[] = 
  1204. {
  1205.   " [--version] [--quiet] [--ignore-init-file] [--nw] [--help] \n",
  1206.   " [-Vqfh] [file]\n",
  1207.   0
  1208. };
  1209.  
  1210. /* Avoid needless messages to stdout. */
  1211. int spread_quietly = 0;
  1212.  
  1213. /* Avoid using X no matter what else. (-x --no-x) */
  1214. int no_x = 0;
  1215.  
  1216. static void
  1217. show_usage ()
  1218. {
  1219.   char ** use = usage;
  1220.   fprintf (stderr, "Usage: %s ", argv_name);
  1221.   while (*use)
  1222.     {
  1223.       fprintf (stderr, "%s\n", *use);
  1224.       ++use;
  1225.     }
  1226. }
  1227.  
  1228. int 
  1229. main (argc, argv)
  1230.      int argc;
  1231.      char **argv;
  1232. {
  1233.   int c;
  1234.   int num;
  1235.   int using_x = 0;
  1236.   int using_curses = 0;
  1237.   int ignore_init_file = 0;
  1238.   FILE * init_fp[2];
  1239.   int init_fpc = 0;
  1240.  
  1241.   argv_name = argv[0];
  1242.   __make_backups = 1;
  1243.  
  1244.   /* Set up the minimal io handler. */
  1245. #if 0
  1246.   cmd_graphics ();
  1247. #endif
  1248.  
  1249.   {
  1250.     int opt;
  1251.     for (opt = getopt_long (argc, argv, short_options, long_options, (int *)0);
  1252.      opt != EOF;
  1253.      opt = getopt_long (argc, argv, short_options, long_options, (int *)0))
  1254.       {
  1255.     switch (opt)
  1256.       {
  1257.       case 'V':
  1258.         fprintf  (stdout, "%s\n", oleo_version_string);
  1259.         break;
  1260.       case 'q':
  1261.         spread_quietly = 1;
  1262.         break;
  1263.       case 'f':
  1264.         ignore_init_file = 1;
  1265.         break;
  1266.       case 'x':
  1267.         no_x = 1;
  1268.         break;
  1269.       case 'h':
  1270.         show_usage ();
  1271.         break;
  1272.       }
  1273.       }
  1274.   }
  1275.   init_infinity ();
  1276.   init_mem ();
  1277.   init_eval ();
  1278.   init_refs ();
  1279.   init_cells ();
  1280.   init_fonts ();
  1281.   obstack_init (¯o_stack);
  1282. #ifdef USE_DLD
  1283.   if (!index (argv_name, '/'))
  1284.     {
  1285.       char *name;
  1286.  
  1287.       name = dld_find_executable (argv_name);
  1288.       num = dld_init (name);
  1289.       free (name);
  1290.     }
  1291.   else
  1292.     num = dld_init (argv_name);
  1293.   if (num)
  1294.     io_error_msg ("dld_init() failed: %s", (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
  1295.   dld_search_path = ":/usr/local/lib/oleo:/lib:/usr/lib:/usr/local/lib";
  1296. #endif
  1297.  
  1298.  
  1299.  
  1300.   /* Find the init files. 
  1301.    * This is done even if ignore_init_file is true because
  1302.    * it effects whether the disclaimer will be shown.
  1303.    */
  1304.     {
  1305.       char *ptr, *home;
  1306.       
  1307.       home = getenv ("HOME");
  1308.       if (home)
  1309.     {
  1310.       ptr = mk_sprintf ("%s/%s", home, RCFILE);
  1311.       init_fp[init_fpc] = fopen (ptr, "r");
  1312.       if (init_fp[init_fpc])
  1313.         ++init_fpc;
  1314.       free (ptr);
  1315.     }
  1316.       
  1317.       init_fp[init_fpc] = fopen (RCFILE, "r");
  1318.       if (init_fp[init_fpc])
  1319.     ++init_fpc;
  1320.     }
  1321.  
  1322.   if (!init_fpc && !spread_quietly)
  1323.     {
  1324.       char ** msg;
  1325.       fputs (oleo_version_string, stdout);
  1326.       for (msg = disclaimer; *msg; ++msg)
  1327.     fputs (*msg, stdout);
  1328.       fflush (stdout);
  1329.     }
  1330.  
  1331.   FD_ZERO (&read_fd_set);
  1332.   FD_ZERO (&read_pending_fd_set);
  1333.   FD_ZERO (&exception_fd_set);
  1334.   FD_ZERO (&exception_pending_fd_set);
  1335.  
  1336. #ifdef HAVE_X11_X_H
  1337.   if (!no_x)
  1338.     get_x11_args (&argc, argv);
  1339.   if (!no_x && io_x11_display_name)
  1340.     {
  1341.       x11_graphics ();
  1342.       using_x = 1;
  1343.     }
  1344.   else
  1345. #endif
  1346.     {
  1347.       tty_graphics ();
  1348.       using_curses = 1;
  1349.       /* Allow the disclaimer to be read. */
  1350.       if (!init_fpc && !spread_quietly)
  1351.     sleep (5);
  1352.     }
  1353.  
  1354.   io_open_display ();
  1355.  
  1356.   init_maps ();
  1357.  
  1358.   if (argc - optind > 1)
  1359.     {
  1360.       show_usage ();
  1361.       exit (1);
  1362.     }
  1363.  
  1364.   /* Read the init file. */
  1365.   {
  1366.     int x;
  1367.     for (x = 0; x < init_fpc; ++x)
  1368.       {
  1369.     if (!ignore_init_file)
  1370.       read_cmds_cmd (init_fp[x]);
  1371.     fclose (init_fp[x]);
  1372.       }
  1373.   }
  1374.  
  1375.   /* These probably don't all need to be ifdef, but
  1376.    * it is harmless.
  1377.    */
  1378. #ifdef SIGINT
  1379.   signal (SIGINT, got_sig);
  1380. #endif
  1381. #ifdef SIGQUIT
  1382.   signal (SIGQUIT, got_sig);
  1383. #endif
  1384. #ifdef SIGILL
  1385.   signal (SIGILL, got_sig);
  1386. #endif
  1387. #ifdef SIGEMT
  1388.   signal (SIGEMT, got_sig);
  1389. #endif
  1390. #ifdef SIGBUS
  1391.   signal (SIGBUS, got_sig);
  1392. #endif
  1393. #ifdef SIGSEGV
  1394.   signal (SIGSEGV, got_sig);
  1395. #endif
  1396. #ifdef SIGPIPE
  1397.   signal (SIGPIPE, got_sig);
  1398. #endif
  1399.  
  1400.   if (argc - optind == 1)
  1401.     {
  1402.       FILE * fp;
  1403.       set_line (&in_line['d' - 'a'], argv[optind]);
  1404.       ++optind;
  1405.       if (fp = fopen (argv[1], "r"))
  1406.     {
  1407.       read_file_and_run_hooks (fp, 0);
  1408.       fclose (fp);
  1409.     }
  1410.       else
  1411.     io_error_msg ("Can't open %s: %s", argv[1], err_msg ());
  1412.     }
  1413.  
  1414.   io_recenter_cur_win ();
  1415.  
  1416.   for (;;)
  1417.     {
  1418.       if (how_many != 1)
  1419.     {
  1420.       how_many = 1;
  1421.       io_update_status ();
  1422.     }
  1423.       io_clear_input_before ();
  1424.       map_chr (MAIN_MAP);
  1425.       if (!rmac)
  1426.     io_clear_input_after ();
  1427.  
  1428.     swtch:
  1429.       if (!cur_cmd)
  1430.     {
  1431.       io_error_msg ("Key %s is unbound in map %s",
  1432.             char_to_string (cur_chr),
  1433.             map_names[last_map]);
  1434.       continue;
  1435.     }
  1436.       if ((cur_cmd->func_flags & NONTOP) == 0)
  1437.     {
  1438.       io_error_msg ("Command '%s' is not appropriate now.", cur_cmd->func_name);
  1439.       continue;
  1440.     }
  1441.       num = global_cmd (MAIN_MAP);
  1442.       if (num == -2)
  1443.     io_error_msg ("Command '%s' is *not* appropriate now.", cur_cmd->func_name);
  1444.       else if (num >= 0)
  1445.     {
  1446.       c = num;
  1447.       goto swtch;
  1448.     }
  1449.     }
  1450. }
  1451.  
  1452. static FILE *
  1453. open_file (prompt, line, mode)
  1454.      char *prompt;
  1455.      struct line *line;
  1456.      char *mode;
  1457. {
  1458.   FILE *fp;
  1459.  
  1460.   if (io_get_line (prompt, line))
  1461.     return 0;
  1462.   if ((fp = xopen_with_backup (line->buf, mode)) == 0)
  1463.     {
  1464.       io_error_msg ("Can't open file '%s':%s", line->buf, err_msg ());
  1465.       return 0;
  1466.     }
  1467.   return fp;
  1468. }
  1469.  
  1470. static void
  1471. close_file (line, fp)
  1472.      struct line *line;
  1473.      FILE *fp;
  1474. {
  1475.   int num;
  1476.  
  1477.   if (num = xclose (fp))
  1478.     io_error_msg ("Can't close '%s': Error code %d: %s", line->buf, num, err_msg ());
  1479. }
  1480.  
  1481. /* Deal with point-n-shoot */
  1482. static int
  1483. get_a_range (whatfor, r, line)
  1484.      char *whatfor;
  1485.      struct rng *r;
  1486.      struct line *line;
  1487. {
  1488.   char *ptr;
  1489.  
  1490.   if (mkrow != NON_ROW)
  1491.     {
  1492.       /* The range has already been selected */
  1493.     got_rng:
  1494.       set_rng (r, mkrow, mkcol, curow, cucol);
  1495.       mkrow = NON_ROW;
  1496.       return 0;
  1497.     }
  1498.   switch (io_get_line (whatfor, line))
  1499.     {
  1500.     case 0:
  1501.       if (mkrow != NON_ROW)
  1502.     goto got_rng;
  1503.       ptr = line->buf;
  1504.       if (get_abs_rng (&ptr, r) || *ptr != '\0')
  1505.     {
  1506.       io_error_msg ("Can't parse '%s'", line->buf);
  1507.       return 1;
  1508.     }
  1509.       return 0;
  1510.     case 1:
  1511.       if (mkrow != NON_ROW)
  1512.     goto got_rng;
  1513.       return 1;
  1514.     case 2:
  1515.       return 1;
  1516. #ifdef TEST
  1517.     default:
  1518.       panic ("io_get_line() what?");
  1519. #endif
  1520.     }
  1521.   return 1;
  1522. }
  1523.  
  1524. static char *
  1525. get_range_and_font (cmd_name, r, line)
  1526.      char *cmd_name;
  1527.      struct rng *r;
  1528.      struct line *line;
  1529. {
  1530.   char *ptr;
  1531.   char *prm;
  1532.   int got_rng = 0;
  1533.   extern char *strdup ();
  1534.  
  1535.   if (mkrow != NON_ROW)
  1536.     {
  1537.       /* We've got the range, just get the string */
  1538.       set_rng (r, mkrow, mkcol, curow, cucol);
  1539.       got_rng++;
  1540.       mkrow = NON_ROW;
  1541.       prm = mk_sprintf ("%s %s to", cmd_name, range_name (r));
  1542.     }
  1543.   else
  1544.     prm = strdup (cmd_name);
  1545.  
  1546.   if (io_get_line (prm, line))
  1547.     {
  1548.       free (prm);
  1549.       return 0;
  1550.     }
  1551.   free (prm);
  1552.  
  1553.   if (mkrow != NON_ROW)
  1554.     {
  1555.       if (got_rng)
  1556.     {
  1557.       io_error_msg ("Two ranges?");
  1558.       return 0;
  1559.     }
  1560.       set_rng (r, mkrow, mkcol, curow, cucol);
  1561.       mkrow = NON_ROW;
  1562.       got_rng++;
  1563.     }
  1564.   ptr = line->buf;
  1565.   if (!got_rng)
  1566.     {
  1567.       if (get_abs_rng (&ptr, r))
  1568.     {
  1569.       io_error_msg ("Can't parse '%s'", line->buf);
  1570.       return 0;
  1571.     }
  1572.       if (*ptr == ',')
  1573.     ptr++;
  1574.     }
  1575.   while (*ptr == ' ')
  1576.     ptr++;
  1577.   if (!*ptr)
  1578.     {
  1579.       if (io_get_line (cmd_name, line))
  1580.     {
  1581.       return 0;
  1582.     }
  1583.       ptr = line->buf;
  1584.     }
  1585.   return ptr;
  1586. }
  1587.  
  1588.  
  1589. static FILE *
  1590. get_range_and_file (whatfor, r, line)
  1591.      char *whatfor;
  1592.      struct rng *r;
  1593.      struct line *line;
  1594. {
  1595.   char *ptr;
  1596.   char *prompt;
  1597.   int got_rng = 0;
  1598.   FILE *ret;
  1599.   extern char *strdup ();
  1600.  
  1601.   if (mkrow != NON_ROW)
  1602.     {
  1603.       /* We've got the range, just get the file */
  1604.       set_rng (r, mkrow, mkcol, curow, cucol);
  1605.       got_rng++;
  1606.       mkrow = NON_ROW;
  1607.       prompt = mk_sprintf ("%s %s to file", whatfor, range_name (r));
  1608.     }
  1609.   else
  1610.     prompt = strdup (whatfor);
  1611.  
  1612.   if (io_get_line (prompt, line))
  1613.     {
  1614.       free (prompt);
  1615.       return 0;
  1616.     }
  1617.   free (prompt);
  1618.  
  1619.   if (mkrow != NON_ROW)
  1620.     {
  1621.       if (got_rng)
  1622.     {
  1623.       io_error_msg ("Two ranges?");
  1624.       return 0;
  1625.     }
  1626.       set_rng (r, mkrow, mkcol, curow, cucol);
  1627.       mkrow = NON_ROW;
  1628.       got_rng++;
  1629.     }
  1630.   ptr = line->buf;
  1631.   if (!got_rng)
  1632.     {
  1633.       if (get_abs_rng (&ptr, r))
  1634.     {
  1635.       io_error_msg ("Can't parse '%s'", line->buf);
  1636.       return 0;
  1637.     }
  1638.       if (*ptr == ',')
  1639.     ptr++;
  1640.     }
  1641.   while (*ptr == ' ')
  1642.     ptr++;
  1643.   if (!*ptr)
  1644.     {
  1645.       if (io_get_line ("To file: ", line))
  1646.     return 0;
  1647.       ptr = line->buf;
  1648.     }
  1649.   ret = xopen_with_backup (ptr, "w");
  1650.   if (!ret)
  1651.     io_error_msg ("Can't open file '%s':%s", ptr, err_msg ());
  1652.   return ret;
  1653. }
  1654.  
  1655.  
  1656. static int
  1657. get_two_ranges (whatfor, one, two, line)
  1658.      char *whatfor;
  1659.      struct rng *one;
  1660.      struct rng *two;
  1661.      struct line *line;
  1662. {
  1663.   char *ptr;
  1664.   char *prompt;
  1665.   int num_got = 0;
  1666.   int n;
  1667.  
  1668.   prompt = 0;
  1669.   if (mkrow != NON_ROW)
  1670.     {
  1671.       /* We've got the first one already */
  1672.       set_rng (one, mkrow, mkcol, curow, cucol);
  1673.       mkrow = NON_ROW;
  1674.       num_got++;
  1675.     }
  1676.  
  1677.   while (num_got != 2)
  1678.     {
  1679.       prompt = (num_got == 1) ? mk_sprintf ("%s %s to", whatfor, range_name (one)) : whatfor;
  1680.       n = io_get_line (prompt, line);
  1681.       if (prompt != whatfor)
  1682.     free (prompt);
  1683.  
  1684.       if (n > 1 || (n == 1 && mkrow == NON_ROW))
  1685.     return 1;
  1686.  
  1687.       if (mkrow != NON_ROW)
  1688.     {
  1689.       if (line->buf[0])
  1690.         {
  1691.           io_error_msg (num_got ? "Extra characters '%s'" : "'%s' is ambiguous", line->buf);
  1692.           return 1;
  1693.         }
  1694.       set_rng (num_got ? two : one, mkrow, mkcol, curow, cucol);
  1695.       mkrow = NON_ROW;
  1696.  
  1697.       num_got++;
  1698.     }
  1699.       else
  1700.     {
  1701.       ptr = line->buf;
  1702.       if (!num_got)
  1703.         {
  1704.           if (get_abs_rng (&ptr, one))
  1705.         {
  1706.           io_error_msg ("Can't parse first range in '%s'", line->buf);
  1707.           return 1;
  1708.         }
  1709.           if (*ptr == ',')
  1710.         ptr++;
  1711.         }
  1712.  
  1713.       if (get_abs_rng (&ptr, two))
  1714.         {
  1715.           if (num_got)
  1716.         {
  1717.           io_error_msg ("Can't find second range in '%s'", line->buf);
  1718.           return 1;
  1719.         }
  1720.           num_got++;
  1721.         }
  1722.       else if (!num_got)
  1723.         num_got += 2;
  1724.       else
  1725.         num_got++;
  1726.     }
  1727.     }
  1728.   if (*ptr)
  1729.     {
  1730.       io_error_msg ("Extra characters in '%s'", line->buf);
  1731.       return 1;
  1732.     }
  1733.  
  1734.   sprint_line (line, "%s %s", range_name (one), range_name (two));
  1735.   return 0;
  1736. }
  1737.  
  1738.  
  1739. #ifdef __STDC__
  1740. void 
  1741. map_chr (int map)
  1742. #else
  1743. void 
  1744. map_chr (map)
  1745.      int map;
  1746. #endif
  1747. {
  1748.   int ch;
  1749.   struct keymap *keymap;
  1750.   struct key *key;
  1751.  
  1752.   keymap = the_maps[map];
  1753.   last_map = map;
  1754.   for (;;)
  1755.     {
  1756.       if (rmac)
  1757.     {
  1758.       int len;
  1759.       unsigned char *ptr;
  1760.  
  1761.     tryagain:
  1762.       deal_alarm ();    /* If an alarm has gone off, deal. */
  1763.       ch = *(rmac->mac_exe++);
  1764.       switch (ch)
  1765.         {
  1766.         case '\0':
  1767.           cur_vector = 0;
  1768.           cur_cmd = end_macro_cmd;
  1769.           cur_chr = 0;
  1770.           return;
  1771.  
  1772.         case 0x80 | 'a':
  1773.           ch = '\0';
  1774.           break;
  1775.  
  1776.         case 0x80 | 'b':
  1777.           ch = '{';
  1778.           break;
  1779.  
  1780.         case '{':
  1781.           for (ptr = rmac->mac_exe;
  1782.            *ptr && *ptr != ' ' && *ptr != '}';
  1783.            ptr++);
  1784.           len = ptr - rmac->mac_exe;
  1785.           for (cur_vector = 0; cur_vector < num_funcs; cur_vector++)
  1786.         for (cur_cmd = &the_funcs[cur_vector][0];
  1787.              cur_cmd->func_name;
  1788.              cur_cmd++)
  1789.           if (!strincmp ((char *) (rmac->mac_exe),
  1790.                  cur_cmd->func_name, len)
  1791.               && cur_cmd->func_name[len] == '\0')
  1792.             {
  1793.               cur_chr = '\0';
  1794.               goto out;
  1795.             }
  1796.           io_error_msg ("Ignoring unknown function '%.*s' in macro",
  1797.                 len, rmac->mac_exe);
  1798.           while (*ptr != '\0' && *ptr != '}')
  1799.         ptr++;
  1800.           if (*ptr == '}')
  1801.         ptr++;
  1802.           rmac->mac_exe = ptr;
  1803.           goto tryagain;
  1804.  
  1805.         out:
  1806.           if (*ptr == ' ')
  1807.         {
  1808.           /* ... add argument support here ... */
  1809.           if (!cur_cmd->func_args)
  1810.             {
  1811.               io_error_msg ("Ignoring extra operand to %s",
  1812.                     cur_cmd->func_name);
  1813.               while (*ptr && *ptr != '}')
  1814.             ptr++;
  1815.               if (*ptr == '}')
  1816.             ptr++;
  1817.             }
  1818.           else if (cur_cmd->func_args[0] == 'n')
  1819.             {
  1820.               how_many = astol ((char **) (&ptr));
  1821.               if (*ptr == '}')
  1822.             ptr++;
  1823.             }
  1824.           else
  1825.             {
  1826.               macro_func_arg = (char *) ptr;
  1827.               while (*ptr && *ptr != '}')
  1828.             ptr++;
  1829.               if (*ptr == '}')
  1830.             *ptr++ = '\0';
  1831.             }
  1832.           rmac->mac_exe = ptr;
  1833.         }
  1834.           else
  1835.         rmac->mac_exe += len + 1;
  1836.           return;
  1837.         }
  1838.     }
  1839.       else
  1840.     ch = real_get_chr ();
  1841.  
  1842.       for (;;)
  1843.     {
  1844.       key = &(keymap->keys[ch]);
  1845.       if (key->vector < 0)
  1846.         if (key->code >= 0)
  1847.           {
  1848.         keymap = the_maps[key->code];
  1849.         last_map = key->code;
  1850.         break;
  1851.           }
  1852.         else if (keymap->map_next)
  1853.           keymap = keymap->map_next;
  1854.         else
  1855.           {
  1856.         cur_vector = 0;
  1857.         cur_cmd = 0;
  1858.         cur_chr = ch;
  1859.         return;
  1860.           }
  1861.       else
  1862.         {
  1863.           cur_vector = key->vector;
  1864.           cur_cmd = &(the_funcs[key->vector][key->code]);
  1865.           cur_chr = ch;
  1866.           return;
  1867.         }
  1868.     }
  1869.     }
  1870. }
  1871.  
  1872. /* Return values:
  1873.    -3    break key!
  1874.    -2    c is inappropriate
  1875.    -1    C is OK
  1876.    0+    New char value is ret-1;
  1877.    */
  1878.  
  1879. int 
  1880. global_cmd (magic)
  1881.      int magic;
  1882. {
  1883.   char *ptr;
  1884.   struct rng fm, to;
  1885.   FILE *fp;
  1886.   static struct line confirm;
  1887.   struct cmd_func *cmd;
  1888.  
  1889.   if (!cur_cmd)
  1890.     return -2;
  1891.   cmd = cur_cmd;
  1892.   if (cmd->func_args)
  1893.     {
  1894.       ptr = cmd->func_args;
  1895.  
  1896.     next_arg:
  1897.       switch (*ptr++)
  1898.     {
  1899.     case 'R':
  1900.       if (get_two_ranges (cmd->func_name, &fm, &to, &in_line[*ptr++ - 'a']))
  1901.         break;
  1902.       (*cmd->func_func) (&fm, &to);
  1903.       break;
  1904.  
  1905.     case 'r':
  1906.       if (get_a_range (cmd->func_name, &to, &in_line[*ptr++ - 'a']))
  1907.         break;
  1908.       (*cmd->func_func) (&to);
  1909.       break;
  1910.  
  1911.     case 't':
  1912.       if (io_get_line (cmd->func_name, &in_line[*ptr++ - 'a']))
  1913.         break;
  1914.       (*cmd->func_func) (in_line[cmd->func_args[1] - 'a'].buf);
  1915.       break;
  1916.  
  1917.     case 'C':
  1918.       if (modified == 0)
  1919.         goto next_arg;
  1920.       set_line (&confirm, "");
  1921.       if (io_get_line ("Are you SURE", &confirm)
  1922.           || (confirm.buf[0] != 'Y' && confirm.buf[0] != 'y'))
  1923.         return -1;
  1924.       goto next_arg;
  1925.  
  1926.     case 'f':
  1927.       fp = open_file (cmd->func_name, &in_line[*ptr - 'a'], ptr + 1);
  1928.       if (!fp)
  1929.         break;
  1930.       (*cmd->func_func) (fp);
  1931.       close_file (&in_line[*ptr++ - 'a'], fp);
  1932.       break;
  1933.  
  1934.     case 'F':
  1935.       fp = get_range_and_file (cmd->func_name, &to, &in_line[*ptr - 'a']);
  1936.       if (!fp)
  1937.         break;
  1938.       (*cmd->func_func) (fp, &to);
  1939.       close_file (&in_line[*ptr++ - 'a'], fp);
  1940.       break;
  1941.  
  1942.     case 'S':
  1943.       {
  1944.         char *cp = get_range_and_font (cmd->func_name, &to, &in_line[*ptr - 'a']);
  1945.         if (!cp)
  1946.           break;
  1947.         (*cmd->func_func) (cp, &to);
  1948.         break;
  1949.       }
  1950.  
  1951.     case 'n':
  1952.       if (!*ptr)
  1953.         (*cmd->func_func) ();
  1954.       else if (*ptr >= '0' && *ptr <= '9')
  1955.         (*cmd->func_func) (*ptr - '0');
  1956.       else if (*ptr >= 'a' && *ptr <= 'z')
  1957.         (*cmd->func_func) ((*ptr - 'a') * 26 + ptr[1] - 'a');
  1958.       else
  1959.         (*cmd->func_func) ();
  1960.       break;
  1961.  
  1962.     case 'T':
  1963.       if (*ptr >= '0' && *ptr <= '9')
  1964.         (*cmd->func_func) (*ptr - '0', cur_chr);
  1965.       else
  1966.         (*cmd->func_func) ();
  1967.       break;
  1968.  
  1969.     case 'N':
  1970.       (*cmd->func_func) (magic);
  1971.       return cur_chr;
  1972.  
  1973.     case '\0':
  1974.       (*cmd->func_func) ();
  1975.       break;
  1976.  
  1977. #ifdef TEST
  1978.     default:
  1979.       panic ("Unknown arg type %s in global_cmd", ptr);
  1980. #endif
  1981.     }
  1982.       if (cmd->func_flags & BRK)
  1983.     return -3;
  1984.       return -1;
  1985.     }
  1986.   else if (cmd->func_func)
  1987.     {
  1988.       if (cmd->func_flags & WTH_CHR)
  1989.     (*cmd->func_func) (cur_chr);
  1990.       else
  1991.     (*cmd->func_func) ();
  1992.       if (cmd->func_flags & BRK)
  1993.     return -3;
  1994.       return -1;
  1995.     }
  1996.   return -2;
  1997. }
  1998.  
  1999. static void 
  2000. write_keys_cmd (fp)
  2001.      FILE *fp;
  2002. {
  2003.   struct keymap *map;
  2004.   int n;
  2005.   int key;
  2006.   int vec;
  2007.   int code;
  2008.  
  2009.   for (n = 0; n < num_maps; n++)
  2010.     {
  2011.       char *def;
  2012.       map = the_maps[n];
  2013.       def = 0;
  2014.       if (map && map->map_next)
  2015.     {
  2016.       for (key = 0; key < num_maps; key++)
  2017.         if (the_maps[key] == map->map_next)
  2018.           {
  2019.         def = map_names[key];
  2020.         break;
  2021.           }
  2022.     }
  2023.       if (def)
  2024.     fprintf (fp, "create-keymap %s %s\n", map_names[n], def);
  2025.       else
  2026.     fprintf (fp, "create-keymap %s\n", map_names[n]);
  2027.     }
  2028.   for (n = 0; n < num_maps; n++)
  2029.     {
  2030.       map = the_maps[n];
  2031.       for (key = 0; key < 256; key++)
  2032.     {
  2033.       vec = map->keys[key].vector;
  2034.       code = map->keys[key].code;
  2035.       if (vec < 0 && code >= 0)
  2036.         fprintf (fp, "bind-key %s %s %s\n",
  2037.              map_names[n],
  2038.              map_names[code],
  2039.              char_to_string (key));
  2040.       else if (vec >= 0)
  2041.         fprintf (fp, "bind-key %s %s %s\n",
  2042.              map_names[n],
  2043.              the_funcs[vec][code].func_name,
  2044.              char_to_string (key));
  2045.     }
  2046.     }
  2047. }
  2048.  
  2049. static void 
  2050. clear_keymap (m)
  2051.      struct keymap *m;
  2052. {
  2053.   int n;
  2054.   for (n = 0; n < 256; n++)
  2055.     {
  2056.       m->keys[n].vector = -1;
  2057.       m->keys[n].code = -1;
  2058.     }
  2059. }
  2060.  
  2061. int 
  2062. map_id (name)
  2063.      char *name;
  2064. {
  2065.   int x;
  2066.   for (x = 0; x < num_maps; ++x)
  2067.     if (!strcmp (name, map_names[x]))
  2068.       return x;
  2069.   return -1;
  2070. }
  2071.  
  2072. static void 
  2073. make_keymap (mapname)
  2074.      char *mapname;
  2075. {
  2076.   char *ptr;
  2077.   int num;
  2078.   struct keymap *linkmap;
  2079.   extern char *strdup ();
  2080.  
  2081.   for (ptr = mapname; *ptr && !isspace (*ptr); ++ptr);
  2082.   linkmap = 0;
  2083.   if (*ptr)
  2084.     {
  2085.       *ptr++ = '\0';
  2086.       for (num = 0; num < num_maps; num++)
  2087.     {
  2088.       if (!strcmp (map_names[num], ptr))
  2089.         {
  2090.           linkmap = the_maps[num];
  2091.           break;
  2092.         }
  2093.     }
  2094.     }
  2095.   for (num = 0; num < num_maps; num++)
  2096.     {
  2097.       if (!strcmp (map_names[num], mapname))
  2098.     {
  2099.       clear_keymap (the_maps[num]);
  2100.       return;
  2101.     }
  2102.     }
  2103.   the_maps = ck_realloc (the_maps, (num_maps + 1) * sizeof (struct keymap *));
  2104.   the_maps[num_maps] = ck_malloc (sizeof (struct keymap));
  2105.   the_maps[num_maps]->map_next = linkmap;
  2106.   {
  2107.     int c;
  2108.     struct key k;
  2109.     k.code = k.vector = -1;
  2110.     for (c = 0; c < 256; ++c)
  2111.       the_maps[num_maps]->keys[c] = k;
  2112.   }
  2113.   map_names = ck_realloc (map_names, (num_maps + 1) * sizeof (char *));
  2114.   map_names[num_maps] = strdup (mapname);
  2115.   num_maps++;
  2116. }
  2117.  
  2118. static void 
  2119. read_cmds_cmd (fp)
  2120.      FILE *fp;
  2121. {
  2122.   char *ptr;
  2123.   int lineno = 0;
  2124.   while (fgets (print_buf, 300, fp))
  2125.     {
  2126.       ptr = (char *)rindex (print_buf, '\n');
  2127.       if (ptr)
  2128.     *ptr = '\0';
  2129.       ++lineno;
  2130.       for (ptr = print_buf; isspace (*ptr); ptr++);
  2131.       if (!*ptr || (*ptr == '#'))
  2132.     continue;
  2133.       execute_cmd (ptr);
  2134.     }
  2135.   if (!feof (fp))
  2136.     io_error_msg ("read-cmds: read error near line %d.", lineno);
  2137. }
  2138.  
  2139. static void
  2140. write_cmd (fp)
  2141.      FILE *fp;
  2142. {
  2143.   (*write_file) (fp, 0);
  2144.   modified = 0;
  2145. }
  2146.  
  2147. static void
  2148. read_cmd (fp)
  2149.      FILE *fp;
  2150. {
  2151.   read_file_and_run_hooks (fp, 0);
  2152. }
  2153.  
  2154. static void
  2155. read_merge_cmd (fp)
  2156.      FILE *fp;
  2157. {
  2158.   (*read_file) (fp, 1);
  2159. }
  2160.  
  2161. static void
  2162. write_reg_cmd (fp, rng)
  2163.      FILE *fp;
  2164.      struct rng *rng;
  2165. {
  2166.   (*write_file) (fp, rng);
  2167. }
  2168.  
  2169. static void
  2170. sort_region_cmd (ptr)
  2171.      char *ptr;
  2172. {
  2173.   struct rng tmp_rng;
  2174.  
  2175.   if (get_abs_rng (&ptr, &sort_rng))
  2176.     {
  2177.       io_error_msg ("Can't find a range to sort in %s", ptr);
  2178.       return;
  2179.     }
  2180.  
  2181.   cur_row = sort_rng.lr;
  2182.   cur_col = sort_rng.lc;
  2183.  
  2184.   while (*ptr == ' ')
  2185.     ptr++;
  2186.   if (!*ptr)
  2187.     {
  2188.       sort_ele.lr = 0;
  2189.       sort_ele.lc = 0;
  2190.       sort_ele.hr = 0;
  2191.       sort_ele.hc = 0;
  2192.     }
  2193.   else if (!parse_cell_or_range (&ptr, &sort_ele))
  2194.     {
  2195.       io_error_msg ("Can't parse elements in %s", ptr);
  2196.       return;
  2197.     }
  2198.   else
  2199.     {
  2200.       sort_ele.lr -= sort_rng.lr;
  2201.       sort_ele.lc -= sort_rng.lc;
  2202.       sort_ele.hr -= sort_rng.lr;
  2203.       sort_ele.hc -= sort_rng.lc;
  2204.     }
  2205.  
  2206.   sort_keys_num = 0;
  2207.   while (*ptr == ' ')
  2208.     ptr++;
  2209.   for (; *ptr;)
  2210.     {
  2211.       if (sort_keys_num == sort_keys_alloc)
  2212.     {
  2213.       sort_keys_alloc++;
  2214.       if (sort_keys_alloc > 1)
  2215.         sort_keys = ck_realloc (sort_keys, sort_keys_alloc * sizeof (struct cmp));
  2216.       else
  2217.         sort_keys = ck_malloc (sizeof (struct cmp));
  2218.     }
  2219.       sort_keys[sort_keys_num].mult = 1;
  2220.       if (*ptr == '+')
  2221.     ptr++;
  2222.       else if (*ptr == '-')
  2223.     {
  2224.       sort_keys[sort_keys_num].mult = -1;
  2225.       ptr++;
  2226.     }
  2227.       if (!*ptr)
  2228.     {
  2229.       sort_keys[sort_keys_num].row = 0;
  2230.       sort_keys[sort_keys_num].col = 0;
  2231.       sort_keys_num++;
  2232.       break;
  2233.     }
  2234.       if (!parse_cell_or_range (&ptr, &tmp_rng) || tmp_rng.lr != tmp_rng.hr || tmp_rng.lc != tmp_rng.hc)
  2235.     {
  2236.       io_error_msg ("Can't parse key #%d in %s", sort_keys_num + 1, ptr);
  2237.       sort_keys_num = -1;
  2238.       return;
  2239.     }
  2240.       sort_keys[sort_keys_num].row = tmp_rng.lr - sort_rng.lr;
  2241.       sort_keys[sort_keys_num].col = tmp_rng.lc - sort_rng.lc;
  2242.       sort_keys_num++;
  2243.  
  2244.       while (*ptr == ' ')
  2245.     ptr++;
  2246.     }
  2247.   if (sort_keys_num == 0)
  2248.     {
  2249.       if (sort_keys_alloc == 0)
  2250.     {
  2251.       sort_keys_alloc++;
  2252.       sort_keys = ck_malloc (sizeof (struct cmp));
  2253.     }
  2254.       sort_keys[0].mult = 1;
  2255.       sort_keys[0].row = 0;
  2256.       sort_keys[0].col = 0;
  2257.       sort_keys_num++;
  2258.     }
  2259.   sort_region ();
  2260.   io_repaint ();
  2261. }
  2262.  
  2263. static void
  2264. set_var (ptr)
  2265.      char *ptr;
  2266. {
  2267.   int num;
  2268.   char *ret;
  2269.  
  2270.   while (*ptr == ' ')
  2271.     ptr++;
  2272.   for (num = 0; ptr[num] && ptr[num] != ' '; num++)
  2273.     ;
  2274.   modified = 1;
  2275.   if (!ptr[num])
  2276.     ret = new_var_value (ptr, num, (char *) 0);
  2277.   else
  2278.     ret = new_var_value (ptr, num, &ptr[num + 1]);
  2279.   if (ret)
  2280.     io_error_msg ("Can't set-variable %s: %s\n", ptr, ret);
  2281. }
  2282.  
  2283. static void
  2284. show_var (ptr)
  2285.      char *ptr;
  2286. {
  2287.   struct var *v;
  2288.   int num;
  2289.  
  2290.   while (*ptr == ' ')
  2291.     ptr++;
  2292.   for (num = 0; ptr[num] && ptr[num] != ' '; num++)
  2293.     ;
  2294.  
  2295.   v = find_var (ptr, num);
  2296.   if (!v || v->var_flags == VAR_UNDEF)
  2297.     {
  2298.       io_error_msg ("There is no '%s'", ptr);
  2299.       return;
  2300.     }
  2301.   if (a0)
  2302.     {
  2303.       if (v->v_rng.lr != v->v_rng.hr || v->v_rng.lc != v->v_rng.hc)
  2304.     /* FOO */ sprintf (print_buf, "%s $%s$%u:$%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr, col_to_str (v->v_rng.hc), v->v_rng.hr);
  2305.       else
  2306.     /* FOO */ sprintf (print_buf, "%s $%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr);
  2307.     }
  2308.   else
  2309.     sprintf (print_buf, "%s %s", v->var_name, range_name (&(v->v_rng)));
  2310.   io_info_msg (print_buf);
  2311.   set_line (&in_line[1], print_buf);
  2312. }
  2313.  
  2314. static void
  2315. show_a_var (name, v)
  2316.      char *name;
  2317.      struct var *v;
  2318. {
  2319.   if (v->var_flags == VAR_UNDEF)
  2320.     return;
  2321.   if (a0)
  2322.     {
  2323.       if (v->v_rng.lr != v->v_rng.hr || v->v_rng.lc != v->v_rng.hc)
  2324.     /* FOO */ io_text_line ("%-20s  $%s$%u:$%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr, col_to_str (v->v_rng.hc), v->v_rng.hr);
  2325.       else
  2326.     /* FOO */ io_text_line ("%-20s  $%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr);
  2327.     }
  2328.   else
  2329.     io_text_line ("%-20s  %s", v->var_name, range_name (&(v->v_rng)));
  2330. }
  2331.  
  2332. static void
  2333. show_all_var ()
  2334. {
  2335.   io_text_start ();
  2336.   io_text_line ("%-20s  Current Value", "Variable Name");
  2337.   for_all_vars (show_a_var);
  2338.   io_text_finish ();
  2339. }
  2340.  
  2341. static FILE * write_variable_fp = 0;
  2342.  
  2343. static void
  2344. write_a_var (name, v)
  2345.      char *name;
  2346.      struct var *v;
  2347. {
  2348.   CELLREF r, c;
  2349.   if (v->var_flags == VAR_UNDEF)
  2350.     return;
  2351.   r = v->v_rng.lr;
  2352.   c = v->v_rng.lc;
  2353.   if (v->var_flags == VAR_CELL)
  2354.     fprintf (write_variable_fp, "%s=%s\n",
  2355.          v->var_name, cell_value_string (r, c));
  2356. }
  2357.  
  2358. static void
  2359. write_variables (fp)
  2360.      FILE * fp;
  2361. {
  2362.   if (write_variable_fp)
  2363.     io_error_msg ("Can't re-enter write_variables.");
  2364.   else
  2365.     {
  2366.       write_variable_fp = fp;
  2367.       for_all_vars (write_a_var);
  2368.       write_variable_fp = 0;
  2369.     }
  2370. }
  2371.  
  2372. static void
  2373. read_variables (fp)
  2374.      FILE * fp;
  2375. {
  2376.   char buf[1024];
  2377.   int lineno = 0;
  2378.   while (fgets (buf, 1024, fp))
  2379.     {
  2380.       char * ptr;
  2381.       for (ptr = buf; *ptr && *ptr != '\n'; ++ptr)
  2382.     ;
  2383.       *ptr = '\0';
  2384.       for (ptr = buf; isspace (*ptr); ptr++)
  2385.     ;
  2386.       if (!*ptr || (*ptr == '#'))
  2387.     continue;
  2388.       {
  2389.     char * var_name = ptr;
  2390.     int var_name_len;
  2391.     char * value_string;
  2392.     while (*ptr && *ptr != '=')
  2393.       ++ptr;
  2394.     if (!*ptr)
  2395.       {
  2396.         io_error_msg ("read-variables: format error near line %d.", lineno);
  2397.         return;
  2398.       }
  2399.     var_name_len = ptr - var_name;
  2400.     ++ptr;
  2401.     value_string = ptr;
  2402.     {
  2403.       struct var * var = find_var (var_name, var_name_len);
  2404.       if (var)
  2405.         {
  2406.           switch (var->var_flags)
  2407.         {
  2408.         case VAR_UNDEF:
  2409.           break;
  2410.         case VAR_CELL:
  2411.           set_cell_formula (value_string,
  2412.                     var->v_rng.lr, var->v_rng.lc);
  2413.           break;
  2414.         case VAR_RANGE:
  2415.           io_error_msg
  2416.             ("read-variables (line %d): ranges not supported.",
  2417.              lineno);
  2418.           break;
  2419.         }
  2420.         }
  2421.     }
  2422.       }
  2423.       ++lineno;
  2424.     }
  2425.   if (!feof (fp))
  2426.     {
  2427.       io_error_msg ("read-variables: read error near line %d.", lineno);
  2428.       return;
  2429.     }
  2430. }
  2431.  
  2432.  
  2433. static void
  2434. shift_cell_cursor (dir)
  2435.      int dir;
  2436. {
  2437.   io_shift_cell_cursor (dir);
  2438. }
  2439.  
  2440.  
  2441. static void
  2442. scroll_cell_cursor (dir)
  2443.      int dir;
  2444. {
  2445.   io_scroll_cell_cursor (dir);
  2446. }
  2447.  
  2448. static void
  2449. repaint ()
  2450. {
  2451.   io_repaint ();
  2452. }
  2453.  
  2454. static void
  2455. recenter_cur_win ()
  2456. {
  2457.   io_recenter_cur_win ();
  2458. }
  2459.  
  2460.  
  2461. static void
  2462. scan_cell_cursor (magic)
  2463.      int magic;
  2464. {
  2465.   CELLREF pos, pos_end, pos_inc;
  2466.   CELL *cp;
  2467.   int over, down;
  2468.  
  2469.  
  2470.   over = colmagic[magic] * how_many;
  2471.   down = rowmagic[magic] * how_many;
  2472.   if (over)
  2473.     {
  2474.       if (over > 0)
  2475.     {
  2476.       pos = max_col (curow);
  2477.       pos_end = MIN_COL;
  2478.       pos_inc = -1;
  2479.     }
  2480.       else
  2481.     {
  2482.       pos = MIN_COL;
  2483.       pos_end = max_col (curow);
  2484.       pos_inc = 1;
  2485.     }
  2486.       for (;;)
  2487.     {
  2488.       for (; ((!(cp = find_cell (curow, pos)) || !GET_TYP (cp))); pos += pos_inc)
  2489.         {
  2490.           if (pos == pos_end)
  2491.         {
  2492.           how_many = 1;
  2493.           pos = MIN_COL;
  2494.           break;
  2495.         }
  2496.         }
  2497.       if (--how_many == 0)
  2498.         break;
  2499.       pos += pos_inc;
  2500.     }
  2501.       io_move_cell_cursor (curow, pos);
  2502.     }
  2503.   else
  2504.     {
  2505.       if (down > 0)
  2506.     {
  2507.       pos = max_row (cucol);
  2508.       pos_end = MIN_ROW;
  2509.       pos_inc = -1;
  2510.     }
  2511.       else
  2512.     {
  2513.       pos = MIN_ROW;
  2514.       pos_end = max_row (cucol);
  2515.       pos_inc = 1;
  2516.     }
  2517.       for (;;)
  2518.     {
  2519.       for (; (!(cp = find_cell (pos, cucol)) || !GET_TYP (cp)); pos += pos_inc)
  2520.         {
  2521.           if (pos == pos_end)
  2522.         {
  2523.           how_many = 1;
  2524.           pos = MIN_ROW;
  2525.           break;
  2526.         }
  2527.         }
  2528.       if (--how_many == 0)
  2529.         break;
  2530.       pos += pos_inc;
  2531.     }
  2532.  
  2533.       io_move_cell_cursor (pos, cucol);
  2534.     }
  2535. }
  2536.  
  2537.  
  2538. char *
  2539. fmt_to_str (fmt)
  2540.      int fmt;
  2541. {
  2542.   char *ptr;
  2543.   static char buf[30];
  2544.   char nbuf[10];
  2545.  
  2546.   if (fmt == FMT_DEF)
  2547.     return "default";
  2548.   if (fmt == FMT_HID)
  2549.     return "hidden";
  2550.   if (fmt == FMT_GPH)
  2551.     return "graph";
  2552.   if ((fmt & PRC_FLT) == PRC_FLT)
  2553.     strcpy (nbuf, "float");
  2554.   else
  2555.     sprintf (nbuf, "%d", (fmt & PRC_FLT));
  2556.   switch (fmt | PRC_FLT)
  2557.     {
  2558.     case FMT_USR:
  2559.       ptr = "user-";
  2560.       sprintf (nbuf, "%d", (fmt & PRC_FLT) + 1);
  2561.       break;
  2562.     case FMT_GEN:
  2563.       ptr = "general.";
  2564.       break;
  2565.     case FMT_DOL:
  2566.       ptr = "dollar.";
  2567.       break;
  2568.     case FMT_CMA:
  2569.       ptr = "comma.";
  2570.       break;
  2571.     case FMT_PCT:
  2572.       ptr = "percent.";
  2573.       break;
  2574.     case FMT_FXT:
  2575.       if ((fmt & PRC_FLT) == 0)
  2576.     return "integer";
  2577.       if (fmt == FMT_FXT)
  2578.     return "decimal";
  2579.       ptr = "fixed.";
  2580.       break;
  2581.     case FMT_EXP:
  2582.       ptr = "exponent.";
  2583.       break;
  2584.     default:
  2585.       io_error_msg ("Unknown format %d (%x)", fmt, fmt);
  2586.       ptr = "UNKNOWN";
  2587.       break;
  2588.     }
  2589.   sprintf (buf, "%s%s", ptr, nbuf);
  2590.   return buf;
  2591. }
  2592.  
  2593. struct fmt
  2594. {
  2595.   int fmt;
  2596.   char **strs;
  2597. };
  2598.  
  2599. static char *def_names[] =
  2600. {"default", "def", "D", 0};
  2601. static char *hid_names[] =
  2602. {"hidden", "hid", "H", 0};
  2603. static char *gph_names[] =
  2604. {"graph", "gph", "*", 0};
  2605. static char *int_names[] =
  2606. {"integer", "int", "I", 0};
  2607. static char *dec_names[] =
  2608. {"decimal", "dec", 0};
  2609.  
  2610. static struct fmt simple[] =
  2611. {
  2612.   {FMT_DEF, def_names},
  2613.   {FMT_HID, hid_names},
  2614.   {FMT_GPH, gph_names},
  2615.   {FMT_FXT - PRC_FLT, int_names},
  2616.   {FMT_FXT, dec_names},
  2617.   {0, 0}
  2618. };
  2619.  
  2620. char *gen_names[] =
  2621. {"general.", "gen.", "G", 0};
  2622. char *dol_names[] =
  2623. {"dollar.", "dol.", "$", 0};
  2624. char *cma_names[] =
  2625. {"comma.", "com.", ",", 0};
  2626. char *pct_names[] =
  2627. {"percent.", "pct.", "%", 0};
  2628. char *fxt_names[] =
  2629. {"fixed.", "fxt.", "F", 0};
  2630. char *exp_names[] =
  2631. {"exponent.", "exp.", "E", 0};
  2632.  
  2633. static struct fmt withprec[] =
  2634. {
  2635.   {FMT_GEN - PRC_FLT, gen_names},
  2636.   {FMT_DOL - PRC_FLT, dol_names},
  2637.   {FMT_CMA - PRC_FLT, cma_names},
  2638.   {FMT_PCT - PRC_FLT, pct_names},
  2639.   {FMT_FXT - PRC_FLT, fxt_names},
  2640.   {FMT_EXP - PRC_FLT, exp_names},
  2641.   {0, 0}
  2642. };
  2643.  
  2644. static int
  2645. str_to_fmt (ptr)
  2646.      char *ptr;
  2647. {
  2648.   struct fmt *f;
  2649.   char **strs;
  2650.   int n;
  2651.   int ret;
  2652.   char *p1, *p2;
  2653.  
  2654.   for (f = simple; f->strs; f++)
  2655.     {
  2656.       for (strs = f->strs; *strs; strs++)
  2657.     {
  2658.       if (*ptr != **strs)
  2659.         continue;
  2660.       for (p1 = ptr, p2 = *strs; *p1 == *p2 && *p1; p1++, p2++)
  2661.         ;
  2662.       if (*p1 == '\0' && *p2 == '\0')
  2663.         return f->fmt;
  2664.     }
  2665.     }
  2666.   if (!strncmp (ptr, "user-", 5))
  2667.     {
  2668.       ptr += 5;
  2669.       n = astol (&ptr);
  2670.       if (*ptr || n < 1 || n > 16)
  2671.     return -1;
  2672.       return n - 1 - PRC_FLT + FMT_USR;
  2673.     }
  2674.   for (f = withprec, ret = 0; !ret && f->strs; f++)
  2675.     {
  2676.       for (strs = f->strs; *strs; strs++)
  2677.     {
  2678.       if (*ptr != **strs)
  2679.         continue;
  2680.       for (p1 = ptr, p2 = *strs; *p2 && *p1 == *p2; p1++, p2++)
  2681.         ;
  2682.       if (!*p2)
  2683.         {
  2684.           ret = f->fmt;
  2685.           ptr = p1;
  2686.           break;
  2687.         }
  2688.     }
  2689.     }
  2690.  
  2691.   if (!ret || !*ptr)
  2692.     return -1;
  2693.   if (!strcmp (ptr, "float") || !strcmp (ptr, "f"))
  2694.     {
  2695.       n = PRC_FLT;
  2696.     }
  2697.   else
  2698.     {
  2699.       n = astol (&ptr);
  2700.       if (*ptr || n < 0 || n > 14)
  2701.     return -1;
  2702.     }
  2703.   return ret + n;
  2704. }
  2705.  
  2706. char *
  2707. jst_to_str (jst)
  2708.      int jst;
  2709. {
  2710.   if (jst == JST_DEF)
  2711.     return "default";
  2712.   if (jst == JST_LFT)
  2713.     return "left";
  2714.   if (jst == JST_RGT)
  2715.     return "right";
  2716.   if (jst == JST_CNT)
  2717.     return "center";
  2718.   return "unknown";
  2719. }
  2720.  
  2721. static int
  2722. chr_to_jst (chr)
  2723.      int chr;
  2724. {
  2725.   if (chr == 'd' || chr == 'D')
  2726.     return JST_DEF;
  2727.   if (chr == 'l' || chr == 'L')
  2728.     return JST_LFT;
  2729.   if (chr == 'r' || chr == 'R')
  2730.     return JST_RGT;
  2731.   if (chr == 'c' || chr == 'C')
  2732.     return JST_CNT;
  2733.   return -1;
  2734. }
  2735.  
  2736. /* parse a range, then turn it into an absolute rng */
  2737. static int
  2738. get_abs_rng (pptr, retp)
  2739.      char **pptr;
  2740.      struct rng *retp;
  2741. {
  2742.   unsigned char n;
  2743.  
  2744.   while (**pptr == ' ')
  2745.     (*pptr)++;
  2746.   if (!**pptr)
  2747.     return 1;
  2748.   cur_row = curow;
  2749.   cur_col = cucol;
  2750.   n = parse_cell_or_range (pptr, retp);
  2751.   if (!n)
  2752.     {
  2753.       struct var *v;
  2754.       char *ptr;
  2755.  
  2756.       ptr = *pptr;
  2757.       while (ptr[n] && ptr[n] != ' ')
  2758.     n++;
  2759.       v = find_var (ptr, n);
  2760.       if (!v)
  2761.     return 1;
  2762.       (*pptr) += n;
  2763.       *retp = v->v_rng;
  2764.     }
  2765.   return 0;
  2766. }
  2767.  
  2768. #ifdef __STDC__
  2769. static void 
  2770. desc_map (struct keymap *map)
  2771. #else
  2772. static void 
  2773. desc_map (map)
  2774.      struct keymap *map;
  2775. #endif
  2776. {
  2777.   int n;
  2778.  
  2779.   io_text_start ();
  2780.   for (n = 0; n < 256; n++)
  2781.     if (map->keys[n].code >= 0)
  2782.       io_text_line ("%s: %d %d %s",
  2783.             char_to_string (n),
  2784.             map->keys[n].vector,
  2785.             map->keys[n].code,
  2786.             (map->keys[n].vector < 0
  2787.              ? "vector"
  2788.              : (the_funcs[map->keys[n].vector]
  2789.             [map->keys[n].code].func_name)));
  2790.   io_text_finish ();
  2791. }
  2792.  
  2793. static void 
  2794. set_usr_fmt (fmtstr)
  2795.      char *fmtstr;
  2796. {
  2797.   int u_num;
  2798.   char *ptr;
  2799.   static struct line usr_line;
  2800.   struct line tmp_line;
  2801.   char *tmp_ptr;
  2802.   char *data_buf[9];
  2803.   int i;
  2804.   static char *names[9] =
  2805.   {
  2806.     "Positive header",
  2807.     "Negative header",
  2808.     "Positive trailer",
  2809.     "Negative trailer",
  2810.     "Zero",
  2811.     "Comma",
  2812.     "Decimal point",
  2813.     "Precision",
  2814.     "Scale-factor"
  2815.   };
  2816.  
  2817.   tmp_line.buf = ck_malloc (10);
  2818.   tmp_line.alloc = 10;
  2819.   tmp_ptr = tmp_line.buf;
  2820.  
  2821.   ptr = fmtstr;
  2822.   u_num = astol (&ptr);
  2823.   if (u_num < 1 || u_num > 16 || *ptr != '\0')
  2824.     {
  2825.       io_error_msg ("Unknown number %s", fmtstr);
  2826.       return;
  2827.     }
  2828.   --u_num;
  2829.  
  2830.   get_usr_stats (u_num, data_buf);
  2831.   for (i = 0; i < 9; i++)
  2832.     {
  2833.       int slen;
  2834.       int prevlen;
  2835.  
  2836.       set_line (&usr_line, data_buf[i]);
  2837.       if (io_get_line (names[i], &usr_line) > 1)
  2838.     return;
  2839.  
  2840.       slen = strlen (usr_line.buf);
  2841.       if (tmp_line.alloc <= (tmp_ptr - tmp_line.buf) + slen)
  2842.     {
  2843.       prevlen = tmp_ptr - tmp_line.buf;
  2844.       tmp_line.alloc += slen + 1;
  2845.       tmp_line.buf = ck_realloc (tmp_line.buf, tmp_line.alloc);
  2846.       tmp_ptr = tmp_line.buf + prevlen;
  2847.     }
  2848.       strcpy (tmp_ptr, usr_line.buf);
  2849.       data_buf[i] = tmp_ptr;
  2850.       while (*tmp_ptr != '\0')
  2851.     tmp_ptr++;
  2852.       tmp_ptr++;
  2853.     }
  2854.  
  2855.   set_usr_stats (u_num, data_buf);
  2856.   free (tmp_line.buf);
  2857.   io_repaint ();
  2858. }
  2859.  
  2860.  
  2861. void
  2862. read_mp_usr_fmt (ptr)
  2863.      char *ptr;
  2864. {
  2865.   int usr_n = -1;
  2866.   int n_chrs = 0;
  2867.   char *p;
  2868.   char *buf[9];
  2869.   int i;
  2870.  
  2871.   for (i = 0; i < 9; i++)
  2872.     buf[i] = "";
  2873.   p = ptr;
  2874.   while (*p == ';')
  2875.     {
  2876.       *p++ = '\0';
  2877.       switch (*p++)
  2878.     {
  2879.     case 'N':
  2880.       usr_n = astol (&p) - 1;
  2881.       break;
  2882.     case 'H':
  2883.       switch (*p++)
  2884.         {
  2885.         case 'P':
  2886.           i = 0;
  2887.           break;
  2888.         case 'N':
  2889.           i = 1;
  2890.           break;
  2891.         default:
  2892.           goto badline;
  2893.         }
  2894.       goto count_chars;
  2895.     case 'T':
  2896.       switch (*p++)
  2897.         {
  2898.         case 'P':
  2899.           i = 2;
  2900.           break;
  2901.         case 'N':
  2902.           i = 3;
  2903.           break;
  2904.         default:
  2905.           goto badline;
  2906.         }
  2907.       goto count_chars;
  2908.  
  2909.     case 'Z':
  2910.       i = 4;
  2911.       goto count_chars;
  2912.  
  2913.     case 'C':
  2914.       i = 5;
  2915.       goto count_chars;
  2916.  
  2917.     case 'D':
  2918.       i = 6;
  2919.       goto count_chars;
  2920.  
  2921.     case 'P':
  2922.       i = 7;
  2923.       goto count_chars;
  2924.  
  2925.     case 'S':
  2926.       i = 8;
  2927.       goto count_chars;
  2928.  
  2929.     count_chars:
  2930.       buf[i] = p;
  2931.       n_chrs++;
  2932.       while (*p && *p != ';')
  2933.         {
  2934.           p++;
  2935.           n_chrs++;
  2936.         }
  2937.       break;
  2938.  
  2939.     default:
  2940.     badline:
  2941.       io_error_msg ("Unknown OLEO line %s", ptr);
  2942.       return;
  2943.     }
  2944.     }
  2945.   if (*p || usr_n < 0 || usr_n > 15)
  2946.     goto badline;
  2947.  
  2948.   set_usr_stats (usr_n, buf);
  2949. }
  2950.  
  2951. /* Modify this to write out *all* the options */
  2952. void
  2953. write_mp_options (fp)
  2954.      FILE *fp;
  2955. {
  2956.   fprintf (fp, "O;%sauto;%sbackground;%sa0;ticks %d\n",
  2957.        auto_recalc ? "" : "no",
  2958.        bkgrnd_recalc ? "" : "no",
  2959.        a0 ? "" : "no",
  2960.        alarm_seconds);
  2961. }
  2962.  
  2963. void 
  2964. read_mp_options (str)
  2965.      char *str;
  2966. {
  2967.   char *np;
  2968.  
  2969.   while (np = (char *)index (str, ';'))
  2970.     {
  2971.       *np = '\0';
  2972.       do_set_option (str);
  2973.       *np++ = ';';
  2974.       str = np;
  2975.     }
  2976.   if (np = (char *)rindex (str, '\n'))
  2977.     *np = '\0';
  2978.   (void) do_set_option (str);
  2979. }
  2980.  
  2981. #ifdef __STDC__
  2982. void
  2983. set_options (char * ptr)
  2984. #else
  2985. void
  2986. set_options (ptr)
  2987.      char *ptr;
  2988. #endif
  2989. {
  2990.   if (do_set_option (ptr))
  2991.     io_recenter_cur_win ();
  2992. }
  2993.  
  2994. void
  2995. play_cell ()
  2996. {
  2997.   CELL *cp;
  2998.   static char buf[20];
  2999.   int ch;
  3000.  
  3001.   cp = find_cell (curow, cucol);
  3002.   if (cp
  3003.       && ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK)
  3004.       || GET_LCK (cp) == LCK_LCK))
  3005.     {
  3006.       io_error_msg ("Cell %s is locked", cell_name (curow, cucol));
  3007.       return;
  3008.     }
  3009.   io_info_msg ("Now playing %s.", cell_name (curow, cucol));
  3010.   while (1)
  3011.     {
  3012.       ch = real_get_chr ();
  3013.       if (ch == EOF || ch == '\027')
  3014.     return;
  3015.       sprintf (buf, "%d", ch);
  3016.       new_value (curow, cucol, buf);
  3017.       modified = 1;
  3018.     }
  3019. }
  3020.  
  3021. static void 
  3022. show_options ()
  3023. {
  3024.   int n;
  3025.   int fmts;
  3026.   char *data_buf[9];
  3027.  
  3028.   extern char *strdup ();
  3029.   extern void show_window_options ();
  3030.   extern int usr_set_fmts ();
  3031.  
  3032.   n = auto_recalc;
  3033.   io_text_start ();
  3034.  
  3035.   io_text_line ("auto-recalculation: %s        Recalculate in background: %s",
  3036.         n ? " on" : "off", bkgrnd_recalc ? "on" : "off");
  3037.   io_text_line ("make backup files:  %s        Copy files into backups:   %s",
  3038.     __make_backups ? " on" : "off", __backup_by_copying ? "on" : "off");
  3039.  
  3040.   io_text_line ("Asynchronous updates every %u ???",
  3041.         alarm_seconds);
  3042.  
  3043.   io_text_line ("Print width:      %5u", print_width);
  3044.  
  3045.   io_text_line ("");
  3046.  
  3047.   (*show_file_opts) ();
  3048.  
  3049.   io_text_line ("");
  3050.   show_window_options ();
  3051.   io_text_line ("");
  3052.  
  3053.   fmts = usr_set_fmts ();
  3054.   if (fmts)
  3055.     {
  3056.       io_text_line ("User-defined formats:");
  3057.       io_text_line ("Fmt    +Hdr    -Hdr   +Trlr   -Trlr    Zero   Comma Decimal  Prec         Scale");
  3058.       for (n = 0; n < 16; n++)
  3059.     {
  3060.       if (fmts & (1 << n))
  3061.         {
  3062.           get_usr_stats (n, data_buf);
  3063.           io_text_line ("%3d %7s %7s %7s %7s %7s %7s %7s %5s %13s",
  3064.                 n + 1,
  3065.                 data_buf[0],
  3066.                 data_buf[1],
  3067.                 data_buf[2],
  3068.                 data_buf[3],
  3069.                 data_buf[4],
  3070.                 data_buf[5],
  3071.                 data_buf[6],
  3072.                 data_buf[7],
  3073.                 data_buf[8]);
  3074.         }
  3075.     }
  3076.     }
  3077.   else
  3078.     io_text_line ("No user-defined formats have been defined");
  3079.  
  3080.   io_text_finish ();
  3081. }
  3082.  
  3083. static int 
  3084. do_set_option (ptr)
  3085.      char *ptr;
  3086. {
  3087.   int set_opt = 1;
  3088.   extern int set_window_option ();
  3089.  
  3090.   while (*ptr == ' ')
  3091.     ptr++;
  3092.   if (!strincmp ("no", ptr, 2))
  3093.     {
  3094.       ptr += 2;
  3095.       set_opt = 0;
  3096.       while (*ptr == ' ')
  3097.     ptr++;
  3098.     }
  3099.   if (!stricmp ("auto", ptr))
  3100.     {
  3101.       auto_recalc = set_opt;
  3102.       return 0;
  3103.     }
  3104.   if (!stricmp ("bkgrnd", ptr) || !stricmp ("background", ptr))
  3105.     {
  3106.       bkgrnd_recalc = set_opt;
  3107.       return 0;
  3108.     }
  3109.   if (!stricmp ("a0", ptr))
  3110.     {
  3111.       a0 = set_opt;
  3112.       io_repaint ();
  3113.       return 0;
  3114.     }
  3115.   if (!stricmp ("backup", ptr))
  3116.     {
  3117.       __make_backups = set_opt;
  3118.       return 0;
  3119.     }
  3120.   if (!stricmp ("bkup_copy", ptr))
  3121.     {
  3122.       __backup_by_copying = set_opt;
  3123.       return 0;
  3124.     }
  3125.   if (set_opt && !strincmp ("ticks ", ptr, 6))
  3126.     {
  3127.       ptr += 6;
  3128.       alarm_seconds = astol (&ptr);
  3129.       return 0;
  3130.     }
  3131.   if (set_opt && !strincmp ("print ", ptr, 6))
  3132.     {
  3133.       ptr += 6;
  3134.       print_width = astol (&ptr);
  3135.       return 0;
  3136.     }
  3137.   if (set_opt && !strincmp ("file ", ptr, 5))
  3138.     {
  3139. #ifdef USE_DLD
  3140.       char *tmpstr;
  3141.       extern char *strdup ();
  3142.  
  3143.       ptr += 5;
  3144.       tmpstr = ck_malloc (strlen (ptr) + 20);
  3145.       if (io_name)
  3146.     {
  3147.       sprintf (tmpstr, "%s.o", ptr);
  3148.       if (dld_unlink_by_file (tmpstr, 0))
  3149.         {
  3150.           io_error_msg ("Couldn't unlink old file format %s: %s", io_name, (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
  3151.           goto bad_file;
  3152.         }
  3153.       free (io_name);
  3154.     }
  3155.       if (!stricmp (ptr, "panic"))
  3156.     {
  3157.       io_name = 0;
  3158.       read_file = panic_read_file;
  3159.       write_file = panic_write_file;
  3160.       set_file_opts = panic_set_options;
  3161.       show_file_opts = panic_show_options;
  3162.       free (tmpstr);
  3163.       return 0;
  3164.     }
  3165.       io_name = strdup (ptr);
  3166.       sprintf (tmpstr, "%s.o", ptr);
  3167.       if (dld_link (tmpstr))
  3168.     {
  3169.       io_error_msg ("Couldn't link new file format %s: %s", io_name, (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
  3170.       goto bad_file;
  3171.     }
  3172.       if (dld_link ("libc.a"))
  3173.     io_error_msg ("Couldn't link libc.a");
  3174.       if (dld_link ("libm.a"))
  3175.     io_error_msg ("Couldn't link libm.a");
  3176.  
  3177.       sprintf (tmpstr, "%s_read_file", ptr);
  3178.       read_file = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;
  3179.       sprintf (tmpstr, "%s_write_file", ptr);
  3180.       write_file = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;
  3181.  
  3182.       sprintf (tmpstr, "%s_set_options", ptr);
  3183.       set_file_opts = (int (*)()) (dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0);
  3184.       sprintf (tmpstr, "%s_show_options", ptr);
  3185.       show_file_opts = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;
  3186.  
  3187.       if (!read_file
  3188.       || !write_file
  3189.       || !set_file_opts
  3190.       || !show_file_opts)
  3191.     {
  3192.       char **missing;
  3193.       int n;
  3194.  
  3195.       missing = dld_list_undefined_sym ();
  3196.       io_text_start ();
  3197.       io_text_line ("Undefined symbols in file format %s:", ptr);
  3198.       io_text_line ("");
  3199.       for (n = 0; n < dld_undefined_sym_count; n++)
  3200.         io_text_line ("%s", missing[n]);
  3201.       io_text_line ("");
  3202.       io_text_finish ();
  3203.       free (missing);
  3204.       io_error_msg ("File format %s has undefined symbols: not loaded", ptr);
  3205.     bad_file:
  3206.       sprintf (tmpstr, "%s.o", io_name);
  3207.       dld_unlink_by_file (io_name, 0);
  3208.       if (io_name)
  3209.         free (io_name);
  3210.       io_name = 0;
  3211.       read_file = panic_read_file;
  3212.       write_file = panic_write_file;
  3213.       set_file_opts = panic_set_options;
  3214.       show_file_opts = panic_show_options;
  3215.     }
  3216.       free (tmpstr);
  3217. #else
  3218.       ptr += 5;
  3219.       if (!stricmp ("oleo", ptr))
  3220.     {
  3221.       read_file = oleo_read_file;
  3222.       write_file = oleo_write_file;
  3223.       set_file_opts = oleo_set_options;
  3224.       show_file_opts = oleo_show_options;
  3225.     }
  3226.       else if (!stricmp ("sylk", ptr))
  3227.     {
  3228.       sylk_a0 = 1;
  3229.       read_file = sylk_read_file;
  3230.       write_file = sylk_write_file;
  3231.       set_file_opts = sylk_set_options;
  3232.       show_file_opts = sylk_show_options;
  3233.     }
  3234.       else if (!stricmp ("sylk-noa0", ptr))
  3235.     {
  3236.       sylk_a0 = 0;
  3237.       read_file = sylk_read_file;
  3238.       write_file = sylk_write_file;
  3239.       set_file_opts = sylk_set_options;
  3240.       show_file_opts = sylk_show_options;
  3241.     }
  3242.       else if (!stricmp ("sc", ptr))
  3243.     {
  3244.       read_file = sc_read_file;
  3245.       write_file = sc_write_file;
  3246.       set_file_opts = sc_set_options;
  3247.       show_file_opts = sc_show_options;
  3248.     }
  3249.       else if (!stricmp ("panic", ptr))
  3250.     {
  3251.       read_file = panic_read_file;
  3252.       write_file = panic_write_file;
  3253.       set_file_opts = panic_set_options;
  3254.       show_file_opts = panic_show_options;
  3255.     }
  3256.       else if (!stricmp ("list", ptr))
  3257.     {
  3258.       read_file = list_read_file;
  3259.       write_file = list_write_file;
  3260.       set_file_opts = list_set_options;
  3261.       show_file_opts = list_show_options;
  3262.       /*if (ptr[4])
  3263.         {
  3264.         ptr+=4;
  3265.         sl_sep=string_to_char(&ptr);
  3266.         } */
  3267.     }
  3268.       else
  3269.     io_error_msg ("Unknown file format %s", ptr);
  3270. #endif
  3271.       return 0;
  3272.     }
  3273. #ifdef USE_DLD
  3274.   else if (!strincmp (ptr, "load ", 5))
  3275.     {
  3276.       char *tmpstr;
  3277.       struct function *new_funs;
  3278.       struct cmd_func *new_cmds;
  3279.       struct keymap **new_maps;
  3280.       void (*init_cmd) ();
  3281.  
  3282.       extern unsigned long dld_get_symbol (char *);
  3283.       extern void add_usr_funs (struct function *);
  3284.  
  3285.       ptr += 5;
  3286.       tmpstr = ck_malloc (strlen (ptr) + 20);
  3287.       sprintf (tmpstr, "%s.o", ptr);
  3288.       if (dld_link (tmpstr))
  3289.     {
  3290.       io_error_msg ("Couldn't link %s: %s", tmpstr, (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
  3291.       free (tmpstr);
  3292.       return 0;
  3293.     }
  3294.       if (dld_link ("libc.a"))
  3295.     io_error_msg ("Couldn't link libc.a");
  3296.       if (dld_link ("libm.a"))
  3297.     io_error_msg ("Couldn't link libm.a");
  3298.  
  3299.       if (dld_undefined_sym_count)
  3300.     {
  3301.       char **missing;
  3302.       int n;
  3303.  
  3304.       missing = dld_list_undefined_sym ();
  3305.       io_text_start ();
  3306.       io_text_line ("Undefined symbols in file format %s:", ptr);
  3307.       io_text_line ("");
  3308.       for (n = 0; n < dld_undefined_sym_count; n++)
  3309.         io_text_line ("%s", missing[n]);
  3310.       io_text_line ("");
  3311.       io_text_finish ();
  3312.       free (missing);
  3313.       io_error_msg ("%d undefined symbols in %s", dld_undefined_sym_count, ptr);
  3314.       dld_unlink_by_file (tmpstr, 0);
  3315.       free (tmpstr);
  3316.       return 0;
  3317.     }
  3318.       sprintf (tmpstr, "%s_funs", ptr);
  3319.       new_funs = (struct function *) dld_get_symbol (tmpstr);
  3320.       if (new_funs)
  3321.     add_usr_funs (new_funs);
  3322.       sprintf (tmpstr, "%s_cmds", ptr);
  3323.       new_cmds = (struct cmd_func *) dld_get_symbol (tmpstr);
  3324.       if (new_cmds)
  3325.     add_usr_cmds (new_cmds);
  3326.       sprintf (tmpstr, "%s_maps", ptr);
  3327.       new_maps = (struct keymap **) dld_get_symbol (tmpstr);
  3328.       if (new_maps)
  3329.     add_usr_maps (new_maps);
  3330.       if (!new_funs && !new_cmds && !new_maps)
  3331.     {
  3332.       io_error_msg ("Couldn't find anything to load in %s", ptr);
  3333.       sprintf (tmpstr, "%s.o", ptr);
  3334.       dld_unlink_by_file (tmpstr, 0);
  3335.     }
  3336.       sprintf (tmpstr, "%s_init", ptr);
  3337.       init_cmd = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;
  3338.       if (init_cmd)
  3339.     (*init_cmd) ();
  3340.       free (tmpstr);
  3341.       return 0;
  3342.     }
  3343. #endif
  3344.   if (set_window_option (set_opt, ptr) == 0)
  3345.     {
  3346.       if ((*set_file_opts) (set_opt, ptr))
  3347.     io_error_msg ("Unknown option '%s'", ptr);
  3348.       return 0;
  3349.     }
  3350.   return 1;
  3351. }
  3352.  
  3353.  
  3354. void 
  3355. execute_cmd (str)
  3356.      char *str;
  3357. {
  3358.   CELL *cp;
  3359.   struct macro *old;
  3360.   struct rng r;
  3361.   char *ptr = str;
  3362.  
  3363.   while (isspace (*str))
  3364.     ++str;
  3365.   if (!*str || *str == '#')
  3366.     return;
  3367.   for (ptr = str; *ptr && *ptr != ' '; ptr++);
  3368.  
  3369.   if (*ptr)
  3370.     *ptr++ = '\0';
  3371.   else
  3372.     ptr = 0;
  3373.  
  3374.   for (cur_vector = 0; cur_vector < num_funcs; cur_vector++)
  3375.     for (cur_cmd = &the_funcs[cur_vector][0]; cur_cmd->func_name; cur_cmd++)
  3376.       if (!stricmp (str, cur_cmd->func_name))
  3377.     {
  3378.       /* these lines stolen from map_char */
  3379.       if (ptr)
  3380.         {
  3381.           if (!cur_cmd->func_args)
  3382.         io_error_msg ("Ignoring extra operand to %s",
  3383.                   cur_cmd->func_name);
  3384.           else if (cur_cmd->func_args[0] == 'n')
  3385.         how_many = astol ((char **) (&ptr));
  3386.           else
  3387.         macro_func_arg = ptr;
  3388.         }
  3389.       cur_chr = '\0';
  3390.       global_cmd (MAIN_MAP);
  3391.       return;
  3392.     }
  3393.  
  3394.   if (get_abs_rng (&str, &r))
  3395.     {
  3396.       io_error_msg ("Unknown command %s", str);
  3397.       return;
  3398.     }
  3399.   if (ptr)
  3400.     {
  3401.       io_error_msg ("Macros can't take arguments");
  3402.       return;
  3403.     }
  3404.  
  3405.   if (!(cp = find_cell (r.lr, r.lc))
  3406.       || GET_TYP (cp) != TYP_STR
  3407.       || cp->cell_str[0] == '\0')
  3408.     return;
  3409.  
  3410.   old = rmac;
  3411.   rmac = (struct macro *) obstack_alloc (¯o_stack, sizeof (struct macro));
  3412.   rmac->mac_prev = old;
  3413.   rmac->mac_rng = r;
  3414.   rmac->mac_row = r.lr;
  3415.   rmac->mac_col = r.lc;
  3416.   (void) obstack_grow (¯o_stack, cp->cell_str, 1 + strlen (cp->cell_str));
  3417.   rmac->mac_exe = (unsigned char *) obstack_finish (¯o_stack);
  3418.   rmac->mac_flags = 0;
  3419. }
  3420.  
  3421. static void
  3422. goto_region (r)
  3423.      struct rng *r;
  3424. {
  3425.   struct rng tmp;
  3426.  
  3427.   if (mkrow != NON_ROW)
  3428.     {
  3429.       CELLREF cx, cy;
  3430.  
  3431.       set_rng (&tmp, curow, cucol, mkrow, mkcol);
  3432.       set_line (&in_line[12], range_name (&tmp));
  3433.       cx = mkrow;
  3434.       mkrow = curow;
  3435.       cy = mkcol;
  3436.       mkcol = cucol;
  3437.       (void) io_move_cell_cursor (cx, cy);
  3438.     }
  3439.   else
  3440.     {
  3441.       set_line (&in_line[12], cell_name (curow, cucol));
  3442.       (void) io_move_cell_cursor (r->lr, r->lc);
  3443.     }
  3444.   if (r->hr != r->lr || r->hc != r->lc)
  3445.     {
  3446.       mkrow = r->hr;
  3447.       mkcol = r->hc;
  3448.       io_update_status ();
  3449.     }
  3450.   else if (mkrow != NON_ROW)
  3451.     {
  3452.       mkrow = NON_ROW;
  3453.       io_update_status ();
  3454.     }
  3455. }
  3456.  
  3457. static void
  3458. upper_left ()
  3459. {
  3460.   struct rng rng;
  3461.   rng.lr = rng.hr = MIN_ROW;
  3462.   rng.lc = rng.hc = MIN_COL;
  3463.   goto_region (&rng);
  3464. }
  3465.  
  3466. static void
  3467. lower_left ()
  3468. {
  3469.   struct rng rng;
  3470.   rng.lr = rng.hr = highest_row ();
  3471.   rng.lc = rng.hc = MIN_COL;
  3472.   goto_region (&rng);
  3473. }
  3474.  
  3475. static void
  3476. upper_right ()
  3477. {
  3478.   struct rng rng;
  3479.   rng.lr = rng.hr = MIN_ROW;
  3480.   rng.lc = rng.hc = highest_col ();
  3481.   goto_region (&rng);
  3482. }
  3483.  
  3484. static void
  3485. lower_right ()
  3486. {
  3487.   struct rng rng;
  3488.   rng.lr = rng.hr = highest_row ();
  3489.   rng.lc = rng.hc = highest_col ();
  3490.   goto_region (&rng);
  3491. }
  3492.  
  3493. static void
  3494. set_default ()
  3495. {
  3496.   int fun;
  3497.   char *ptr;
  3498.   int num;
  3499.  
  3500.   sprint_line (&wid_line, "%u", default_width);
  3501.   sprint_line (&hgt_line, "%u", default_height);
  3502.  
  3503.   set_line (&fmt_line, fmt_to_str (default_fmt));
  3504.   io_info_msg ("Alignment %s   Format %s   %slocked  Width %u  Height %u",
  3505.            jst_to_str (default_jst),
  3506.            fmt_line.buf,
  3507.            default_lock == LCK_LCK ? "" : "un",
  3508.            default_width,
  3509.            default_height);
  3510.  
  3511.   fun = io_get_chr ("[A]lignment, [F]ormat, [P]rotection [W]idth, or [H]eight  ");
  3512.   switch (fun)
  3513.     {
  3514.     case 'w':
  3515.     case 'W':
  3516.       if (io_get_line ("set-default-width", &wid_line))
  3517.     break;
  3518.       ptr = wid_line.buf;
  3519.       num = astol (&ptr);
  3520.       if (num < 1)
  3521.     io_error_msg ("Can't set default width to '%s'", wid_line.buf);
  3522.       else
  3523.     {
  3524.       default_width = num;
  3525.       io_recenter_all_win ();
  3526.       return;
  3527.     }
  3528.       break;
  3529.  
  3530.     case 'h':
  3531.     case 'H':
  3532.       if (io_get_line ("set-default height", &hgt_line))
  3533.     break;
  3534.       ptr = hgt_line.buf;
  3535.       num = astol (&ptr);
  3536.       if (num < 1)
  3537.     io_error_msg ("Can't set default height to '%s'", hgt_line.buf);
  3538.       else
  3539.     {
  3540.       default_height = num;
  3541.       io_recenter_all_win ();
  3542.       return;
  3543.     }
  3544.       break;
  3545.  
  3546.     case 'p':
  3547.     case 'P':
  3548.     case 'l':
  3549.     case 'L':
  3550.       fun = io_get_chr ("[P]rotected, or [U]nprotected");
  3551.       if (fun == 'p' || fun == 'P')
  3552.     default_lock = LCK_LCK;
  3553.       else if (fun == 'u' || fun == 'U')
  3554.     default_lock = LCK_UNL;
  3555.       else            /* if (main_map[fun]!=BREAK_CMD) */
  3556.     io_error_msg ("Unknown char '%s'", char_to_string (fun));
  3557.       break;
  3558.  
  3559.     case 'f':
  3560.     case 'F':
  3561.       if (io_get_line ("set-default-format", &fmt_line))
  3562.     break;
  3563.       num = str_to_fmt (fmt_line.buf);
  3564.       if (num == -1 || num == FMT_DEF)
  3565.     {
  3566.       io_error_msg ("Unknown format '%s'", fmt_line.buf);
  3567.       break;
  3568.     }
  3569.       default_fmt = num;
  3570.       io_repaint ();
  3571.       return;
  3572.  
  3573.     case 'a':
  3574.     case 'A':
  3575.       fun = io_get_chr ("[L]eft, [R]ight, or [C]enter");
  3576.       num = chr_to_jst (fun);
  3577.       if (num != -1 && num != JST_DEF)
  3578.     {
  3579.       default_jst = num;
  3580.       io_repaint ();
  3581.       return;
  3582.     }
  3583.       else            /* if (main_map[fun]!=BREAK_CMD) */
  3584.     io_error_msg ("Unknown Alignment '%s'", char_to_string (fun));
  3585.       break;
  3586.  
  3587.     default:
  3588.       /* if (main_map[fun]!=BREAK_CMD) */
  3589.       io_error_msg ("Unknown command '%s'", char_to_string (fun));
  3590.       /* else
  3591.      io_error_msg(""); */
  3592.       break;
  3593.     }
  3594.   io_update_status ();
  3595. }
  3596.  
  3597. void 
  3598. format_area (f)
  3599.      struct rng *f;
  3600. {
  3601.   int c;
  3602.   int fmt, jst, wid, hgt;
  3603.   CELLREF cc;
  3604.   char *locked;
  3605.   CELL *cp;
  3606.   int fun;
  3607.   char *ptr;
  3608.  
  3609.   cp = find_cell (f->lr, f->lc);
  3610.   if (!cp)
  3611.     {
  3612.       fmt = FMT_DEF;
  3613.       jst = JST_DEF;
  3614.     }
  3615.   else
  3616.     {
  3617.       fmt = GET_FMT (cp);
  3618.       jst = GET_JST (cp);
  3619.     }
  3620.  
  3621.   wid = get_nodef_width (f->lc);
  3622.   if (wid == 0)
  3623.     set_line (&wid_line, "def");
  3624.   else
  3625.     sprint_line (&wid_line, "%d", wid - 1);
  3626.  
  3627.   hgt = get_nodef_height (f->lr);
  3628.   if (hgt == 0)
  3629.     set_line (&hgt_line, "def");
  3630.   else
  3631.     sprint_line (&hgt_line, "%d", hgt - 1);
  3632.  
  3633.   set_line (&fmt_line, fmt_to_str (fmt));
  3634.   set_line_to_nice_font_name (&font_line, cp ? cp->cell_font : 0);
  3635.  
  3636.   if (!cp || GET_LCK (cp) == LCK_DEF)
  3637.     locked = (default_lock == LCK_UNL ? "unlocked(def)" : "locked(def)");
  3638.   else if (GET_LCK (cp) == LCK_UNL)
  3639.     locked = "unlocked";
  3640.   else if (GET_LCK (cp) == LCK_LCK)
  3641.     locked = "locked";
  3642.   else
  3643.     locked = "Huh What?";
  3644.  
  3645.   io_info_msg ("Alignment %s   Format %s   Width %s   Height %s  %s",
  3646.            jst_to_str (jst),
  3647.            fmt_line.buf,
  3648.            wid_line.buf,
  3649.            hgt_line.buf,
  3650.            locked);
  3651.  
  3652.   fun =
  3653.     io_get_chr
  3654.     ("[A]lignment, [F]ormat, f[O]nt, [P]rotection, [H]eight or [W]idth  ");
  3655.   switch (fun)
  3656.     {
  3657.     case 'f':
  3658.     case 'F':
  3659.       if (io_get_line ("set-format", &fmt_line))
  3660.     break;
  3661.       fmt = str_to_fmt (fmt_line.buf);
  3662.       if (fmt != -1)
  3663.     format_region (f, fmt, -1);
  3664.       else
  3665.     io_error_msg ("Unknown format '%s'", fmt_line.buf);
  3666.       break;
  3667.  
  3668.     case 'o':
  3669.     case 'O':
  3670.       if (io_get_line ("set-font", &font_line))
  3671.     break;
  3672.       set_area_font_cmd (font_line.buf, f);
  3673.       break;
  3674.  
  3675.     case 'a':
  3676.     case 'A':
  3677.       c = io_get_chr ("Align [L]eft, [R]ight, [C]enter, or [D]efault");
  3678.       fun = chr_to_jst (c);
  3679.       if (fun != -1)
  3680.     format_region (f, -1, fun);
  3681.       else            /* if (main_map[c]!=BREAK_CMD) */
  3682.     io_error_msg ("Unknown Justify '%s'", char_to_string (c));
  3683.       break;
  3684.  
  3685.     case 'p':
  3686.     case 'P':
  3687.     case 'l':
  3688.     case 'L':
  3689.       c = io_get_chr ("[D]efault, [P]rotect, or [U]nprotect");
  3690.       if (c == 'd' || c == 'D')
  3691.     lock_region (f, LCK_DEF);
  3692.       else if (c == 'p' || c == 'P')
  3693.     lock_region (f, LCK_LCK);
  3694.       else if (c == 'u' || c == 'U')
  3695.     lock_region (f, LCK_UNL);
  3696.       else            /* if (main_map[c]!=BREAK_CMD) */
  3697.     io_error_msg ("Unknown lock %s", char_to_string (c));
  3698.       break;
  3699.  
  3700.     case 'w':
  3701.     case 'W':
  3702.       if (io_get_line ("set-width", &wid_line))
  3703.     break;
  3704.       ptr = wid_line.buf;
  3705.       if (*ptr == 'd' || *ptr == 'D')
  3706.     fun = 0;
  3707.       else if (isdigit (*ptr))
  3708.     fun = astol (&ptr) + 1;
  3709.       else
  3710.     {
  3711.       io_error_msg ("Unknown width '%s'", wid_line.buf);
  3712.       break;
  3713.     }
  3714.       for (cc = f->lc;; cc++)
  3715.     {
  3716.       set_width (cc, fun);
  3717.       if (cc == f->hc)
  3718.         break;
  3719.     }
  3720.       io_recenter_all_win ();
  3721.       return;
  3722.     case 'h':
  3723.     case 'H':
  3724.       if (io_get_line ("set height", &hgt_line))
  3725.     break;
  3726.       ptr = hgt_line.buf;
  3727.       if (*ptr == 'd' || *ptr == 'D')
  3728.     fun = 0;
  3729.       else
  3730.     {
  3731.       fun = astol (&ptr) + 1;
  3732.       if (*ptr)
  3733.         {
  3734.           io_error_msg ("Unknown height '%s'", hgt_line.buf);
  3735.           break;
  3736.         }
  3737.     }
  3738.       for (cc = f->lr;; cc++)
  3739.     {
  3740.       set_height (cc, fun);
  3741.       if (cc == f->hr)
  3742.         break;
  3743.     }
  3744.       io_recenter_all_win ();
  3745.       return;
  3746.  
  3747.     default:
  3748.       /* if (main_map[fun]!=BREAK_CMD) */
  3749.       io_error_msg ("Unknown command '%s'", char_to_string (fun));
  3750.       break;
  3751.     }
  3752.   io_update_status ();
  3753. }
  3754.  
  3755. void
  3756. insert_row ()
  3757. {
  3758.   struct rng from;
  3759.   struct rng to;
  3760.   if ((how_many > (MAX_ROW - curow)) || (how_many < 0))
  3761.     {
  3762.       io_error_msg ("insert-row: prefix argument out of range.");
  3763.       return;
  3764.     }
  3765.   from.lc = MIN_COL;
  3766.   from.hc = MAX_COL;
  3767.   from.lr = curow;
  3768.   from.hr = MAX_ROW - how_many;
  3769.   to.lc = MIN_COL;
  3770.   to.hc = MIN_COL;
  3771.   to.lr = curow + how_many;
  3772.   to.hr = curow + how_many;
  3773.   move_region (&from, &to);
  3774. }
  3775.  
  3776. void
  3777. insert_col ()
  3778. {
  3779.   struct rng from;
  3780.   struct rng to;
  3781.   if ((how_many > (MAX_COL - cucol)) || (how_many < 0))
  3782.     {
  3783.       io_error_msg ("insert-col: prefix argument out of range.");
  3784.       return;
  3785.     }
  3786.   from.lr = MIN_ROW;
  3787.   from.hr = MAX_ROW;
  3788.   from.lc = cucol;
  3789.   from.hc = MAX_COL - how_many;
  3790.   to.lr = MIN_ROW;
  3791.   to.hr = MIN_ROW;
  3792.   to.lc = cucol + how_many;
  3793.   to.hc = cucol + how_many;
  3794.   move_region (&from, &to);
  3795. }
  3796.  
  3797. void
  3798. delete_row ()
  3799. {
  3800.   struct rng from;
  3801.   struct rng to;
  3802.   if ((how_many < 0) || (how_many > (MAX_ROW - curow + 1)))
  3803.     {
  3804.       io_error_msg ("delete-row: prefix argument out of range.");
  3805.       return;
  3806.     }
  3807.   from.lc = MIN_COL;
  3808.   from.hc = MAX_COL;
  3809.   from.lr = curow + how_many;
  3810.   from.hr = MAX_ROW;
  3811.   to.lc = MIN_COL;
  3812.   to.hc = MIN_COL;
  3813.   to.lr = curow;
  3814.   to.hr = curow;
  3815.   move_region (&from, &to);
  3816. }
  3817.  
  3818. void
  3819. delete_col ()
  3820. {
  3821.   struct rng from;
  3822.   struct rng to;
  3823.   if ((how_many < 0) || (how_many > (MAX_COL - cucol + 1)))
  3824.     {
  3825.       io_error_msg ("delete-col: prefix argument out of range.");
  3826.       return;
  3827.     }
  3828.   from.lr = MIN_ROW;
  3829.   from.hr = MAX_ROW;
  3830.   from.lc = cucol + how_many;
  3831.   from.hc = MAX_COL;
  3832.   to.lr = MIN_ROW;
  3833.   to.hr = MIN_ROW;
  3834.   to.lc = cucol;
  3835.   to.hc = cucol;
  3836.   move_region (&from, &to);
  3837. }
  3838.  
  3839.  
  3840. #ifdef __STDC__
  3841. static RETSIGTYPE
  3842. got_sig (int sig)
  3843. #else
  3844. static RETSIGTYPE
  3845. got_sig (sig)
  3846.      int sig;
  3847. #endif
  3848. {
  3849. }
  3850.  
  3851. #if 0
  3852. static void
  3853. got_sigint (ign)
  3854.      int ign;
  3855. {
  3856.   int ch;
  3857.  
  3858.   ch = io_get_chr ("Panic save and exit?");
  3859.   if (ch == 'y' || ch == 'Y')
  3860.     got_sig ();
  3861. }
  3862. #endif
  3863.  
  3864. static void
  3865. start_macro ()
  3866. {
  3867.   if (making_macro)
  3868.     {
  3869.       io_error_msg ("Can't define two macros at once");
  3870.       return;
  3871.     }
  3872.   making_macro_size = 20;
  3873.   making_macro = making_macro_start = ck_malloc (5 + making_macro_size);
  3874.   /* *making_macro++='"'; */
  3875. }
  3876.  
  3877. static void
  3878. end_macro ()
  3879. {
  3880.   union vals z;
  3881.   struct rng to;
  3882.   CELL *cp;
  3883.   struct macro *old;
  3884.   static struct line macro_line;
  3885.  
  3886.   if (!rmac && !making_macro)
  3887.     {
  3888.       io_error_msg ("Not executing or defining a macro!");
  3889.       return;
  3890.     }
  3891.   if (rmac)
  3892.     {
  3893.       if (rmac->mac_row == rmac->mac_rng.hr && rmac->mac_col == rmac->mac_rng.hc)
  3894.     {
  3895.       old = rmac->mac_prev;
  3896.       (void) obstack_free (¯o_stack, rmac);
  3897.       rmac = old;
  3898.       goto deal_making;
  3899.     }
  3900.  
  3901.       if (rmac->mac_row == rmac->mac_rng.hr)
  3902.     {
  3903.       rmac->mac_row = rmac->mac_rng.lr;
  3904.       rmac->mac_col++;
  3905.     }
  3906.       else
  3907.     rmac->mac_row++;
  3908.       if (!(cp = find_cell (rmac->mac_row, rmac->mac_col)) || GET_TYP (cp) != TYP_STR || cp->cell_str[0] == '\0')
  3909.     {
  3910.       old = rmac->mac_prev;
  3911.       (void) obstack_free (¯o_stack, rmac);
  3912.       rmac = old;
  3913.       goto deal_making;
  3914.     }
  3915.       (void) obstack_grow (¯o_stack, cp->cell_str, 1 + strlen (cp->cell_str));
  3916.       rmac->mac_exe = (unsigned char *) obstack_finish (¯o_stack);
  3917.       rmac->mac_flags = 0;
  3918.     }
  3919. deal_making:
  3920.   if (!making_macro)
  3921.     return;
  3922.  
  3923.  
  3924.   making_macro[0] = '\0';
  3925.   making_macro = 0;
  3926.   if (get_a_range ("Put macro where", &to, ¯o_line))
  3927.     io_error_msg ("Forgetting new macro");
  3928.   else
  3929.     {
  3930.       z.c_s = (char *) making_macro_start;
  3931.       set_new_value (to.lr, to.lc, TYP_STR, &z);
  3932.     }
  3933.   free (making_macro_start);
  3934. }
  3935.  
  3936. static void
  3937. quit_cmd ()
  3938. {
  3939.   io_close_display ();
  3940. #ifndef AMIGA
  3941. #ifdef FASYNC
  3942.   fcntl (0, F_SETFL, term_flag);
  3943. #endif
  3944. #ifdef FIOSSAIOSTAT
  3945.   if ((term_flag & 1) == 0)
  3946.     {
  3947.       int i = 0;
  3948.  
  3949.       ioctl (0, FIOSSAIOSTAT, &i);
  3950.     }
  3951.   if ((term_flag & 2) == 0)
  3952.     {
  3953.       int i = 0;
  3954.  
  3955.       ioctl (0, FIOSNBIO, &i);
  3956.     }
  3957. #endif
  3958. #endif
  3959.   exit (0);
  3960. }
  3961.  
  3962. static void
  3963. bound_macro (num)
  3964.      int num;
  3965. {
  3966.   struct macro *old;
  3967.   CELL *cp;
  3968.   /* CELLREF rr,cc; */
  3969.  
  3970.   cp = find_cell (bound_macros[num].lr, bound_macros[num].lc);
  3971.   if (!cp || GET_TYP (cp) != TYP_STR || cp->cell_str[0] == '\0')
  3972.     return;
  3973.   old = rmac;
  3974.   rmac = (struct macro *) obstack_alloc (¯o_stack, sizeof (struct macro));
  3975.   rmac->mac_prev = old;
  3976.   rmac->mac_rng = bound_macros[num];
  3977.   rmac->mac_row = bound_macros[num].lr;
  3978.   rmac->mac_col = bound_macros[num].lc;
  3979.   (void) obstack_grow (¯o_stack, cp->cell_str, 1 + strlen (cp->cell_str));
  3980.   rmac->mac_exe = (unsigned char *) obstack_finish (¯o_stack);
  3981.   rmac->mac_flags = 0;
  3982. }
  3983.  
  3984. static void
  3985. mark_cell_cmd ()
  3986. {
  3987.   mkrow = curow;
  3988.   mkcol = cucol;
  3989.   io_update_status ();
  3990. }
  3991.  
  3992. static void
  3993. unmark_cmd ()
  3994. {
  3995.   mkrow = NON_ROW;
  3996.   mkcol = NON_COL;
  3997.   io_update_status ();
  3998. }
  3999.  
  4000. static void
  4001. recalc_cmd ()
  4002. {
  4003.   current_cycle++;
  4004.   while (eval_next_cell ())
  4005.     ;
  4006. }
  4007.  
  4008. static void
  4009. desc_key_cmd ()
  4010. {
  4011.   io_error_msg ("Key:  ");
  4012.   map_chr (MAIN_MAP);
  4013.   if (!cur_cmd)
  4014.     io_info_msg ("%s is unbound", char_to_string (cur_chr));
  4015.   else
  4016.     io_info_msg ("%s --> %s", char_to_string (cur_chr), cur_cmd->func_name);
  4017. }
  4018.  
  4019. static void 
  4020. bind_key_cmd (text)
  4021.      char *text;
  4022. {
  4023.   int map;
  4024.   int c;
  4025.   short vec;
  4026.   short code;
  4027.   char *ptr;
  4028.   char *cmdstr;
  4029.   struct rng rng;
  4030.   struct cmd_func *tmpfunc;
  4031.   static struct line tmpline;
  4032.  
  4033.   for (ptr = text; *ptr && !isspace (*ptr); ptr++);
  4034.   if (!*ptr)
  4035.     {
  4036.       if (io_get_line ("Command", &tmpline))
  4037.     return;
  4038.       ptr = tmpline.buf;
  4039.     }
  4040.   else
  4041.     *ptr++ = '\0';
  4042.   while (*ptr == ' ')
  4043.     ptr++;
  4044.   cmdstr = ptr;
  4045.   while (*ptr && *ptr != ' ')
  4046.     ptr++;
  4047.   if (!*ptr)
  4048.     c = io_get_chr ("Key:  ");
  4049.   else
  4050.     {
  4051.       *ptr++ = '\0';
  4052.       c = string_to_char (&ptr);
  4053.       if (c < 0)
  4054.     {
  4055.       io_error_msg ("Illegal character '%s'", ptr);
  4056.       goto fail;
  4057.     }
  4058.     }
  4059.  
  4060.   for (map = 0; map < num_maps; map++)
  4061.     if (!strcmp (text, map_names[map]))
  4062.       break;
  4063.   if (map == num_maps)
  4064.     {
  4065.       io_error_msg ("Can't find keymap '%s'", text);
  4066.       goto fail;
  4067.     }
  4068.   for (vec = 0; vec < num_funcs; vec++)
  4069.     {
  4070.       for (code = 0; the_funcs[vec][code].func_name; code++)
  4071.     if (!stricmp (cmdstr, the_funcs[vec][code].func_name))
  4072.       goto fini;
  4073.     }
  4074.   for (code = 0; code < num_maps; code++)
  4075.     {
  4076.       if (!strcmp (cmdstr, map_names[code]))
  4077.     {
  4078.       vec = -1;
  4079.       goto fini;
  4080.     }
  4081.     }
  4082.   if (get_abs_rng (&cmdstr, &rng))
  4083.     {
  4084.       io_error_msg ("Unknown command '%s'", cmdstr);
  4085.       goto fail;
  4086.     }
  4087.  
  4088.   vec = bound_macro_vec;
  4089.   for (code = 0; code < n_bound_macros; code++)
  4090.     {
  4091.       if (!bcmp (&bound_macros[code], &rng, sizeof (struct rng)))
  4092.       goto fini;
  4093.     }
  4094.  
  4095.   ptr = range_name (&rng);
  4096.   if (!bound_macro_vec)
  4097.     {
  4098.       bound_macros = ck_malloc (sizeof (struct rng));
  4099.       n_bound_macros = 1;
  4100.       tmpfunc = ck_malloc (sizeof (struct cmd_func));
  4101.       bound_macro_vec = add_usr_cmds (tmpfunc);
  4102.     }
  4103.   else
  4104.     {
  4105.       n_bound_macros++;
  4106.       bound_macros = ck_realloc (bound_macros, n_bound_macros * sizeof (struct rng));
  4107.       the_funcs[bound_macro_vec] = ck_realloc (the_funcs[bound_macro_vec], n_bound_macros * sizeof (struct cmd_func));
  4108.       tmpfunc = &the_funcs[bound_macro_vec][n_bound_macros - 1];
  4109.     }
  4110.   bound_macros[n_bound_macros - 1] = rng;
  4111.   tmpfunc->func_args = ck_malloc (strlen (ptr) + 5);
  4112.   tmpfunc->func_args[0] = 'n';
  4113.   tmpfunc->func_args[1] = 'a' + (n_bound_macros - 1) / 26;
  4114.   tmpfunc->func_args[2] = 'a' + (n_bound_macros - 1) % 26;
  4115.   tmpfunc->func_args[3] = '\0';
  4116.   tmpfunc->func_name = tmpfunc->func_args + 4;
  4117.   strcpy (tmpfunc->func_name, ptr);
  4118.   tmpfunc->func_flags = ALL;
  4119.   tmpfunc->func_func = bound_macro;
  4120. fini:
  4121.   do_bind_key (the_maps[map], c, vec, code);
  4122. fail:
  4123.   sprint_line (&in_line[16], "%s %s %s", text, cmdstr, char_to_string (c));
  4124. }
  4125.  
  4126. static void 
  4127. do_bind_key (m, key, vector, code)
  4128.      struct keymap *m;
  4129.      int key;
  4130.      int vector;
  4131.      int code;
  4132. {
  4133.   m->keys[key].vector = (short)vector;
  4134.   m->keys[key].code = (short)code;
  4135. }
  4136.  
  4137. static void 
  4138. interact_macro_cmd ()
  4139. {
  4140.   io_error_msg ("Command not implemented");
  4141.   return;
  4142. }
  4143.  
  4144. static void 
  4145. kill_cell_cmd ()
  4146. {
  4147.   CELL *cp;
  4148.  
  4149.   cp = find_cell (curow, cucol);
  4150.   if (!cp)
  4151.     return;
  4152.   if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
  4153.     {
  4154.       io_error_msg ("Cell %s is locked", cell_name (curow, cucol));
  4155.       return;
  4156.     }
  4157.   new_value (curow, cucol, "");
  4158.   cp->cell_flags = 0;
  4159.   cp->cell_font = 0;
  4160.   modified = 1;
  4161. }
  4162.  
  4163. static void
  4164. format_cell_cmd ()
  4165. {
  4166.   struct rng to;
  4167.  
  4168.   to.lr = to.hr = curow;
  4169.   to.lc = to.hc = cucol;
  4170.   format_area (&to);
  4171. }
  4172.  
  4173. static void
  4174. kill_all_cmd ()
  4175. {
  4176.   clear_spreadsheet ();
  4177.   io_repaint ();
  4178. }
  4179.  
  4180. static void
  4181. do_input_cmd (n, c)
  4182.      int n;
  4183.      int c;
  4184. {
  4185.   CELL *cp;
  4186.   char *fail;
  4187.  
  4188.   switch (n)
  4189.     {
  4190.       /* Edit cell */
  4191.     case 0:
  4192.       if (cp = find_cell (curow, cucol))
  4193.     {
  4194.       set_line (&val_line, decomp (curow, cucol, cp));
  4195.       decomp_free ();
  4196.     }
  4197.       else
  4198.     set_line (&val_line, "");
  4199.       break;
  4200.  
  4201.       /* Edit Cell Value */
  4202.     case 1:
  4203.       set_line (&val_line, cell_value_string (curow, cucol));
  4204.       break;
  4205.  
  4206.     case 2:            /* Set-cell */
  4207.       set_line (&val_line, "x");
  4208.       val_line.buf[0] = c;
  4209.       break;
  4210.  
  4211.       /* New Def Cell */
  4212.     case 3:
  4213.       break;
  4214. #ifdef TEST
  4215.     default:
  4216.       panic ("Unknown value in do_input_cell (%d)", n);
  4217. #endif
  4218.     }
  4219.   cp = find_cell (curow, cucol);
  4220.   if (((!cp || GET_LCK (cp) == LCK_DEF) && default_lock == LCK_LCK) || (cp && GET_LCK (cp) == LCK_LCK))
  4221.     {
  4222.       io_error_msg ("Cell %s is locked", cell_name (curow, cucol));
  4223.       return;
  4224.     }
  4225.   setrow = curow;
  4226.   setcol = cucol;
  4227.   if (io_get_line ("set-cell", &val_line) > 1)
  4228.     return;
  4229.   fail = new_value (setrow, setcol, val_line.buf);
  4230.   if (fail)
  4231.     io_error_msg (fail);
  4232.   else
  4233.     modified = 1;
  4234. }
  4235.  
  4236. static void
  4237. set_region_formula (str, rng)
  4238.      char * str;
  4239.      struct rng * rng;
  4240. {
  4241.   CELLREF row, col;
  4242.  
  4243.   for (row = rng->lr; row <= rng->hr; ++row)
  4244.     for (col = rng->lc; col <= rng->hc; ++col)
  4245.       {
  4246.     char * error = new_value (row, col, str);
  4247.     if (error)
  4248.       {
  4249.         io_error_msg (error);
  4250.         return;
  4251.       }
  4252.     else
  4253.       modified = 1;
  4254.       }
  4255. }
  4256.  
  4257. #if __STDC__
  4258. static void
  4259. set_cell_formula (char * str, CELLREF row, CELLREF col)
  4260. #else
  4261. static void
  4262. set_cell_formula (str, row, col)
  4263.      char * str;
  4264.      CELLREF row, col;
  4265. #endif
  4266. {
  4267.   char * error = new_value (row, col, str);
  4268.   if (error)
  4269.     {
  4270.       io_error_msg (error);
  4271.       return;
  4272.     }
  4273.   else
  4274.     modified = 1;
  4275. }
  4276.  
  4277.  
  4278.  
  4279. static void
  4280. do_break_cmd ()
  4281. {
  4282.   if (mkrow != NON_ROW)
  4283.     {
  4284.       mkrow = NON_ROW;
  4285.       how_many = 1;
  4286.       io_update_status ();
  4287.     }
  4288. }
  4289.  
  4290. static void 
  4291. digit_cmd (magic)
  4292.      int magic;
  4293. {
  4294.   struct keymap *map;
  4295.  
  4296.   map = the_maps[DIGIT_MAP];
  4297.   map->map_next = the_maps[magic];
  4298.   how_many = 0;
  4299.   do
  4300.     {
  4301.       how_many = how_many * 10 + cur_cmd - digit_0_cmd;
  4302.       io_update_status ();
  4303.       map_chr (DIGIT_MAP);
  4304.     }
  4305.   while (cur_cmd >= digit_0_cmd && cur_cmd <= digit_9_cmd);
  4306. }
  4307.  
  4308.  
  4309.  
  4310.  
  4311. static void 
  4312. set_area_font_cmd (name, rng)
  4313.      char *name;
  4314.      struct rng *rng;
  4315. {
  4316.   struct font_memo *f = intern_font (name);
  4317.   set_area_font (rng, f);
  4318. }
  4319.  
  4320.  
  4321. static void 
  4322. set_cell_font_cmd (name)
  4323.      char *name;
  4324. {
  4325.   struct rng to;
  4326.  
  4327.   to.lr = to.hr = curow;
  4328.   to.lc = to.hc = cucol;
  4329.   set_area_font_cmd (name, &to);
  4330. }
  4331.  
  4332. struct page_size 
  4333. {
  4334.     char *name;
  4335.     float wid;
  4336.     float hgt;
  4337. };
  4338.  
  4339. static struct page_size size_table[] =
  4340. {
  4341.   { "letter",       612,  792     }, /* (8.5 x 11  in.)   */
  4342.   { "tabloid",      792,  1224    }, /* (11 x 17  in.)    */
  4343.   { "ledger",       1224, 792     }, /* (17 x 11  in.)    */
  4344.   { "legal",        612,  1008    }, /* (8.5 x 14  in.)   */
  4345.   { "statement",    396,  612     }, /* (5.5 x 8.5 in.)   */
  4346.   { "executive",    540,  720     }, /* (7.5 x 10  in.)   */
  4347.   { "a3",           842,  1190    },
  4348.   { "a4",           595,  842     },
  4349.   { "latex-a4",     523,  770     }, /* A4 - 1in margins all round */
  4350.   { "a5",           420,  595     },
  4351.   { "b4",           729,  1032    },
  4352.   { "b5",           516,  729     },      
  4353.   { "folio",        612,  936     }, /* (8.5 x 13  in.)   */
  4354.   { "quarto",       610,  780     }
  4355. };
  4356.  
  4357. #ifdef __STDC__
  4358. static struct page_size *
  4359. find_size( char * size, int len )
  4360. #else
  4361. static struct page_size *
  4362. find_size( size, len )
  4363.      char *size;
  4364.      int len;
  4365. #endif
  4366. {
  4367.   int i;
  4368.   struct page_size *p = size_table;
  4369.   
  4370.   for (i = 0;
  4371.        i < sizeof(size_table)/sizeof(struct page_size);
  4372.        i++, p++)
  4373.     if (strincmp (size, p->name, len) == 0 )
  4374.       return p;
  4375.   return 0;
  4376. }
  4377.  
  4378. static float default_pswid = 8.5 * 72.;
  4379. static float default_pshgt = 11. * 72.;
  4380.  
  4381. #ifdef __STDC__
  4382. static void
  4383. set_page_size_cmd (char * whole_str)
  4384. #else
  4385. static void
  4386. set_page_size_cmd (whole_str)
  4387.      char * whole_str;
  4388. #endif
  4389. {
  4390.   char * str = whole_str;
  4391.   float neww;
  4392.   float newh;
  4393.   while (*str && isspace(*str))
  4394.     ++str;
  4395.   if (!isdigit (*str) && *str != '.')
  4396.     {
  4397.       char * end = str;
  4398.       struct page_size * ps;
  4399.       while (*end && !isspace(*end))
  4400.     ++end;
  4401.       ps = find_size (str, end - str);
  4402.       if (ps)
  4403.     {
  4404.       default_pswid = ps->wid;
  4405.       default_pshgt = ps->hgt;
  4406.       return;
  4407.     }
  4408.       io_error_msg
  4409.     ("Bad page size (should look like `8.5 x 11' or `21.6 x 28c'): %s.",
  4410.      whole_str);
  4411.       return;
  4412.     }
  4413.   neww = atof (str);
  4414.   while (*str && isdigit(*str))
  4415.     ++str;
  4416.   if (*str == '.')
  4417.     {
  4418.       ++str;
  4419.       while (isdigit (*str))
  4420.     ++str;
  4421.     }
  4422.   while (*str && isspace(*str))
  4423.     ++str;
  4424.   if (*str == 'x')
  4425.     {
  4426.       ++str;
  4427.       while (*str && isspace(*str))
  4428.     ++str;
  4429.     }
  4430.   if (!isdigit (*str) && *str != '.')
  4431.     {
  4432.       io_error_msg
  4433.     ("Bad page size (should look like `8.5 x 11' or `21.6 x 28c'): %s.",
  4434.      whole_str);
  4435.       return;
  4436.     }
  4437.   newh = atof (str);
  4438.   while (*str && isdigit(*str))
  4439.     ++str;
  4440.   if (*str == '.')
  4441.     {
  4442.       ++str;
  4443.       while (*str && isdigit (*str))
  4444.     ++str;
  4445.     }
  4446.   while (*str && isspace(*str))
  4447.     ++str;
  4448.   if (*str == 'c')
  4449.     {
  4450.       neww *= .3937;
  4451.       newh *= .3937;
  4452.     }
  4453.   if (*str != 'p')
  4454.     {
  4455.       default_pswid = neww * 72;
  4456.       default_pshgt = newh * 72;
  4457.     }
  4458. }
  4459.  
  4460. void 
  4461. psprint_region_cmd (fp, rng)
  4462.      FILE *fp;
  4463.      struct rng *rng;
  4464. {
  4465.   psprint_region (fp, rng, default_pswid, default_pshgt, 0);
  4466. }
  4467.  
  4468. /* This is a bit kludgey. Input line editting has its own event loop (grr!),
  4469.  * and all of its state is private.  These mouse commands can't entirely
  4470.  * handle it when the target is in the input line.  In that case, they
  4471.  * save the decoded mouse event where io_get_line can pick it up:
  4472.  */
  4473. struct mouse_event last_mouse_event;
  4474.  
  4475. static void
  4476. do_mouse_goto ()
  4477. {
  4478.   if (last_mouse_event.location >= 0 && last_mouse_event.downp)
  4479.     {
  4480.       nicely_goto_window (last_mouse_event.location);
  4481.       io_move_cell_cursor (last_mouse_event.r, last_mouse_event.c);
  4482.     }
  4483. }
  4484.  
  4485. static void
  4486. do_mouse_mark ()
  4487. {
  4488.   if (last_mouse_event.location >= 0 && last_mouse_event.downp)
  4489.     {
  4490.       mkrow = last_mouse_event.r;
  4491.       mkcol = last_mouse_event.c;
  4492.     }
  4493. }
  4494.  
  4495.  
  4496. static void
  4497. do_mouse_mark_and_goto ()
  4498. {
  4499.   if (last_mouse_event.location >= 0 && last_mouse_event.downp)
  4500.     {
  4501.       mkrow = curow;
  4502.       mkcol = cucol;
  4503.       nicely_goto_window (last_mouse_event.location);
  4504.       io_move_cell_cursor (last_mouse_event.r, last_mouse_event.c);
  4505.     }
  4506. }
  4507.  
  4508. static void
  4509. do_mouse_cmd (fn)
  4510.      void (*fn) ();
  4511. {
  4512.   int seq = real_get_chr ();
  4513.   dequeue_mouse_event (&last_mouse_event, seq);
  4514.   fn ();
  4515. }
  4516.  
  4517. static void
  4518. mouse_mark_cmd ()
  4519. {
  4520.   do_mouse_cmd (do_mouse_mark);
  4521. }
  4522.  
  4523.  
  4524. int was_mouse_goto = 0;
  4525. static void
  4526. mouse_goto_cmd ()
  4527. {
  4528.   do_mouse_cmd (do_mouse_goto);
  4529.   was_mouse_goto = 1;
  4530. }
  4531.  
  4532. static void
  4533. mouse_mark_and_goto_cmd ()
  4534. {
  4535.   do_mouse_cmd (do_mouse_mark_and_goto);
  4536. }
  4537.